我有一个对象编辑器 View ,该 View 显示简单数据以及值的解释,该值使用TemplateSelector进行模板化。如果原始值得到更新,则解释后的值也将更新,反之亦然。在一个简单的DataTemplate中,它可以很好地工作,但是我有一个更复杂的场景,其中值(一个ushort)代表一个位图(标志字段)。为此,我将ItemsControl与ItemTemplate一起使用。这在value-> flags方向上正常,但在单击标志时无效。我在MVVM世界中,所以不想对xaml.cs文件中的事件使用react...
View 的资源:
<DataTemplate x:Key="StandardTemplate">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<TextBox Margin="0" VerticalAlignment="Top" Width="50" Text="{Binding Formatted,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="BitmapTemplate" >
<ItemsControl ItemsSource="{Binding Flags,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel HorizontalAlignment="Center" Width="20">
<TextBlock Text="{Binding BitPosition,Converter={StaticResource intConverter},ConverterParameter=1}" HorizontalAlignment="Center" />
<CheckBox HorizontalAlignment="Center" HorizontalContentAlignment="Center" IsChecked="{Binding IsBitSet,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
<selectors:EditTemplateSelector x:Key="EditSelector" BitmapTemplate="{StaticResource BitmapTemplate}" StandardTemplate="{StaticResource StandardTemplate}" />
它出现在 View 上:
<ContentPresenter Content="{Binding Register}" Grid.Row="2" Grid.ColumnSpan="2" Margin="10" ContentTemplateSelector="{StaticResource EditSelector}" />
我的Bitmap和BitmapBit类是:
public class BitmapBit : ObservableObject
{
ushort _bitPosition = 0;
bool _isSet = false;
public BitmapBit(ushort bitPos, bool isSet)
{
_bitPosition = bitPos;
_isSet = isSet;
}
public ushort BitPosition
{
get { return _bitPosition; }
set
{
if (_bitPosition == value)
return;
_bitPosition = value;
RaisePropertyChanged("BitPosition");
}
}
public bool IsBitSet
{
get { return _isSet; }
set
{
if (_isSet == value)
return;
_isSet = value;
RaisePropertyChanged("IsBitSet");
}
}
}
/// <summary>
/// A collection of BitmapBits
/// </summary>
public class Bitmap : ObservableCollection<BitmapBit>
{
const ushort NUMBER_OF_BITS = sizeof(ushort) * 8; // 8 BITS_IN_A_BYTE
protected Bitmap(ushort value) : base()
{
for (ushort i = 0; i < NUMBER_OF_BITS; ++i )
Insert(0, new BitmapBit(bitPos: i, isSet: (value & (1 << i)) != 0));
}
public static Bitmap Create(ushort value)
{
return new Bitmap(value);
}
public static ushort Parse(Bitmap bits)
{
ushort generated = 0;
foreach (BitmapBit bit in bits)
generated += (ushort)(bit.IsBitSet ? 2 ^ bit.BitPosition : 0);
return generated;
}
}
IsBitSet设置程序被调用,但我认为问题在于位图未包含在Bit更改的通知中-因此,标志设置程序永远不会被调用。当ObservableCollection的成员更改时,如何更新/通知Flags属性?
最佳答案
这是因为您的复选框正在更新由转换器创建的BitmapBit
对象。他们对转换器本身一无所知,转换器本身是由ItemsControl单独调用的。
如果您想更新原始的ushort,那么您真的想直接从ViewModel而不是通过转换器公开BitmapBit
集合。这样,您可以更新将VM引用保留在BitmapBit
对象中,并更新BitmapBit
setter中的ushort。
编辑:
您的编辑已将其清除了一点,但问题仍然几乎是我要解决的问题。 BitmapBits不知道底层的位图,因此请不要对其进行更新。
您没有显示Flags
的定义,因此我无法显示如何更新它,但是基本上您需要做的就是像订阅View一样监视每个BitmapBit的更改,方法是订阅PropertyChanged:
protected Bitmap(ushort value) : base()
{
for (ushort i = 0; i < NUMBER_OF_BITS; ++i )
{
var bit = new BitmapBit(bitPos: i, isSet: (value & (1 << i)) != 0);
bit.PropertyChanged += (s, e) => UpdateFlags();
Insert(0, bit);
}
}