这是我的情况:
我有一个DataGrid
,其中有两列,分别代表纬度和经度。 ItemsSource
绑定到模型类CustomVertex
的集合,该模型类包含两个属性:X
和Y
,它们是double
。
我有三种格式,这些值可以是:小数度,度分和度分秒。我有三个与之对应的RadioButtons
,根据选择的哪个,它将通过Converter将DataGrid
单元格的值更改为正确的格式。
我在MaskedTextBox
的单元格中使用Xceed的DataGrid
,并且将Mask
属性绑定到ViewModel
中的字符串属性以更改{{1 }}只要格式更改。这确实会更改掩码,但是会清除Mask
本身中的所有值,而不是对其进行转换。 MaskedTextBox
中的任何用户输入也不会触发任何东西。
首先,这里是MaskedTextBox
模型:
CustomVertex
这是我的窗口.xaml中的public class CustomVertex : ValidatableModel
{
/// <summary>
/// Represents the X-Coordinate (Longitude)
/// </summary>
private double _x;
public double X
{
get { return _x; }
set
{
if (_x != value)
{
_x = value;
RaisePropertyChanged("X");
}
}
}
/// <summary>
/// Represents the Y-Coordinate (Latitude)
/// </summary>
private double _y;
public double Y
{
get { return _y; }
set
{
if (_y != value)
{
_y = value;
RaisePropertyChanged("Y");
}
}
}
public CustomVertex(double latitude, double longitude)
{
Y = latitude;
X = longitude;
}
public CustomVertex()
{
Y = 0;
X = 0;
}
}
(此处仅显示纬度列,而经度列则完全相同)。我还包括了DataGrid
,以防万一:
RadioButton
这里是<RadioButton Name="degRB" Checked="VertexFormatRB_Checked" IsChecked="{Binding Path=SelectedVertexType, Converter={StaticResource EBConverter}, ConverterParameter={x:Static enums:VertexType.DDD}}" GroupName="UnitType" Content="Deg" />
<RadioButton Name="degMinRB" Checked="VertexFormatRB_Checked" IsChecked="{Binding Path=SelectedVertexType, Converter={StaticResource EBConverter}, ConverterParameter={x:Static enums:VertexType.DDDMM}}" GroupName="UnitType" Content="Deg Min"/>
<RadioButton Name="degMinSecRB" Checked="VertexFormatRB_Checked" IsChecked="{Binding Path=SelectedVertexType, Converter={StaticResource EBConverter}, ConverterParameter={x:Static enums:VertexType.DDDMMSS}}" GroupName="UnitType" Content="Deg Min Sec"/>
<DataGrid ItemsSource="{Binding Vertices}" AutoGenerateColumns="False" IsReadOnly="False">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Latitude" IsReadOnly="False">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<xctk:MaskedTextBox Mask="{Binding DataContext.Mask, RelativeSource={RelativeSource AncestorType={x:Type Window}}}">
<xctk:MaskedTextBox.Text>
<MultiBinding Converter="{StaticResource VertexConverter}" UpdateSourceTrigger="Default">
<Binding Path="Y" />
<Binding Path="DataContext.SelectedVertexType" RelativeSource="{RelativeSource FindAncestor, AncestorType=Window}" />
</MultiBinding>
</xctk:MaskedTextBox.Text>
</xctk:MaskedTextBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
,用于将VertexConverter
的值切换为正确的格式。我从Y
中遗漏了一些东西,但是您应该明白要点:
ConvertBack
最后,public sealed class VertexConverter : IMultiValueConverter
{
private VertexType vertexType = VertexType.DDD;
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values[0] == DependencyProperty.UnsetValue)
{
return null;
}
if ((VertexType)values[1] == VertexType.DDD)
{
vertexType = VertexType.DDD;
return Math.Round((double)values[0], 9).ToString();
}
else if ((VertexType)values[1] == VertexType.DDDMM)
{
vertexType = VertexType.DDDMM;
double dd = Math.Truncate((double)values[0]);
double mm = Math.Round(((double)values[0] - dd) * 60, 7);
return dd + "°" + " " + mm + '"';
}
else if ((VertexType)values[1] == VertexType.DDDMMSS)
{
vertexType = VertexType.DDDMMSS;
return DecimalDegreesHelper.GetDegreesMinutesSecondsFromDecimalDegree((double)values[0]).ToString();
}
else
{
return "";
}
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
object[] ret = new object[2];
if (vertexType == VertexType.DDD)
{
ret[0] = double.Parse(value.ToString());
ret[1] = vertexType;
}
else if (vertexType == VertexType.DDDMM)
{
//more stuff
}
else
{
//more stuff
}
return ret;
}
}
的必要部分:
ViewModel
枚举本身:
const string DDD_MASK = "####.#########"; //ex: -170.112233440
const string DDDMM_MASK = ""; //todo
const string DDDMMSS_MASK = ""; //todo
public ObservableCollection<CustomVertex> Vertices { get; set; } //DataGrid is bound to this. Set to new collection in vm's constructor
private VertexType _selectedVertexType;
public VertexType SelectedVertexType
{
get => _selectedVertexType;
set
{
_selectedVertexType = value;
if (value == VertexType.DDD)
{
Mask = DDD_MASK;
}
else if (value == VertexType.DDDMM)
{
Mask = DDDMM_MASK;
}
else if (value == VertexType.DDDMMSS)
{
Mask = DDDMMSS_MASK;
}
OnPropertyChanged();
}
}
public string Mask { get; set; }
我尝试从public enum VertexType
{
DDD,
DDDMM,
DDDMMSS
}
中取出Mask
的值,并为ViewModel
属性使用另一个Converter
,但这引发了相同的错误。
旁注-如果这不是强制正确输入用户的最佳方法,那么我欢迎其他想法。