I much appreciate the answers from Thomas Levesque and lukas. They contained some useful insight and examples. I'm posting this as an answer because I want to provide more info and an example solution. As with many computing/UI problems, compromises often have to be made. I made the unfortunate discovery that none of the InputScopeNameValues (MSDN InputScopeNameValue Enumeration) switch between decimal (.) and comma (,) when changing region+language settings (and, yes, I double-checked that the keyboard was set on my phone to only use Deutsch).

However, because these TextBox inputs are numeric and need to entered quickly, the numeric InputScopes are still the best way to go. Interestingly, even if the user is forced to use the decimal point in place of a comma, as soon as it's entered in the TextBox the string format changes, e.g. from ".123" to ",123" even though as shown"{0:#.000}". Thus the compromise and in the code below, the workaround (tested so far in en-US and de-DE).
Note: As lukas mentioned, it is always wise to validate user input. I'm not using TryParse here (although I may) so I don't have to rewrite a lot of code. This is mitigated in the UI by choosing a numeric InputScope and in the handling code via try/catch blocks, which even handle correctly a user attempting to bypass the numeric input by pasting text from the clipboard:
<TextBox x:Name="myTBox" InputScope="Number" Text="{Binding SomeNumber, Mode=TwoWay}" />
And code:
public string SomeNumber
{
get
{
return String.Format("{0:#.000}", SomeProfileModel.Instance.SomeProfile.SomeNumber);
}
set
{
if (SomeProfileModel.Instance.SomeProfile.SomeNumber.ToString() == value) return;
var oldValue = SomeProfileModel.Instance.SomeProfile.SomeNumber;
try
{
double newValue;
try
{
newValue = Convert.ToDouble(value, CultureInfo.CurrentCulture);
}
catch (Exception)
{
newValue = Convert.ToDouble(value, CultureInfo.InvariantCulture);
}
if (Convert.ToDouble(MyAppParams.SomeNumberMin, CultureInfo.InvariantCulture) > newValue || Convert.ToDouble(MyAppParams.SomeNumberMax, CultureInfo.InvariantCulture) < newValue)
{
// Revert back to previous value
// NOTE: This has to be done here. If done in the catch statement,
// it will never run since the MessageBox interferes with it.
throw new Exception();
}
SomeProfileModel.Instance.SomeProfile.SomeNumber = newValue;
RaisePropertyChanged("SomeNumber", oldValue, newValue, true);
}
catch (Exception err)
{
System.Windows.MessageBox.Show("Value must be a number between " + MyAppParams.SomeNumberMin + " and " + MyAppParams.SomeNumberMax);
}
}
}