Here is a proof in a more 'constructive' form that can be directly applied to any real-world programming language. Just to make clear, a property of programs must be a predicate that only depends on the halting and output behaviour, in other words two equivalent programs will have exactly the same properties. I will use $X \equiv Y$ to denote that two programs are equivalent, and so $P$ is a property iff $P$ is a predicate and $P(X)=P(Y)$ for any programs $X \equiv Y$.
For any property $P$ of programs such that $P(T)$ and $\neg P(F)$ for some programs $T$,$F$:
If $P$ is decidable:
Let $D$ be a program that decides $P$
Let $M$ be the following program on input $x$:
Create $N$ to be the following program on input $y$:
If $x$ is an invalid program: Return "" [may be unnecessary in some languages]
Return $x(x)(y)$ [using closures or some interpreter written in the language itself]
If D(N): Return F
Return T
Let $R$ be the program that $M(M)$ creates in the variable $N$
Clearly $R \equiv M(M)$
Also $M(M)$ halts because $D$ halts on all inputs
Thus $M(M) \equiv T \vee M(M) \equiv F$
$P(M(M)) \Leftrightarrow P(R) \Leftrightarrow D(R) = True \Leftrightarrow M(M) \equiv F \Leftrightarrow \neg P(M(M))$
Contradiction
Therefore $P$ is not decidable