WPF MVVM有IValueConverter的替代方案
本文关键字:方案 IValueConverter MVVM WPF | 更新日期: 2023-09-27 18:10:18
我有几组可观察的项目集合,它们在后台线程上定期更新(30到60秒)。这些集合通过视图上的ItemsControls显示。控件中的父项和项有几个显示属性,这些属性与每个项的状态相关联。
- 状态将决定文本旁边显示的形状以及该形状的描边和填充颜色。
- 状态将决定该项目文本的背景颜色和文本颜色。
- 状态将决定是否在项目中显示倒计时计时器(计时器与视图模型没有关联)
- 状态可以决定父容器的边框颜色。
我目前在每个属性的单独IValueConverters中执行此逻辑。它工作,但感觉笨重和分散。我几乎想以某种方式订阅UI中的PropertyChanged事件,并让它调用一个方法来呈现该项目的所有显示,以便所有逻辑都包含在一个地方。是否有更好的方法来做到这一点,或者我应该坚持IValueConverters?
这是我所拥有的一个例子。
public ObservableCollection<PanelItem> PanelItems1
{
get { return panelItems1; }
set
{
panelItems1 = value;
base.OnPropertyChanged("PanelItems1");
}
}
PanelItem是一个小的属性集合,包括:名称,值(状态),描述。ItemsControls类似于以下内容:
<Border Grid.Row="0" Grid.Column="0"
BorderBrush="{Binding Path=PanelGroup1.HighestStatus, Converter={StaticResource ParentBorderColorConverter}}"
BorderThickness="3" Height="Auto" Width="Auto" Margin="0,0,2,0">
<StackPanel Grid.Column="0" Grid.Row="0">
<Label Grid.Row="0" Grid.Column="0" Content="First Group" Style="{StaticResource panelTitle}" />
<ItemsControl ItemsSource="{Binding Path=PanelItems1, Mode=TwoWay}"
ItemTemplate="{StaticResource PanelItemTemplate}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel IsItemsHost="True" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
<!-- Here is the Data Template -->
<DataTemplate x:Key="PanelItemTemplate">
<Viewbox MaxHeight="20" HorizontalAlignment="Left" Cursor="Hand">
<WrapPanel>
<Path Margin="2,2,2,2" StrokeThickness="2">
<Path.Data>
<Binding Path="Status" Mode="OneWay" Converter="{StaticResource ShapeConverter}" />
</Path.Data>
<Path.Fill>
<Binding Path="Status" Mode="OneWay" Converter="{StaticResource ShapeColorConverter}" />
</Path.Fill>
<Path.Stroke>
<Binding Path="Status" Mode="OneWay" Converter="{StaticResource ShapeBorderConverter}" />
</Path.Stroke>
</Path>
<ContentPresenter Content="{Binding Path=Name}" Margin="5,0,0,0" />
</WrapPanel>
</Viewbox>
</DataTemplate>
</StackPanel>
</Border>
为什么不声明一个普通的类来实现Status
对象的INotifyPropertyChanged
接口呢?只需添加所需的属性,如Geometry
, Fill
和Stroke
等。如果你这样做了,你就不需要任何Converter
类,你可以这样做:
<DataTemplate x:Key="PanelItemTemplate">
<Viewbox MaxHeight="20" HorizontalAlignment="Left" Cursor="Hand" >
<WrapPanel>
<Path Margin="2,2,2,2" StrokeThickness="2" >
<Path.Data>
<Binding Path="Status.Geometry" Mode="OneWay" />
</Path.Data>
<Path.Fill>
<Binding Path="Status.Fill" Mode="OneWay" />
</Path.Fill>
<Path.Stroke>
<Binding Path="Status.Stroke" Mode="OneWay" />
</Path.Stroke>
</Path>
<ContentPresenter Content="{Binding Path=Name}" Margin="5,0,0,0" />
</WrapPanel>
</Viewbox>
</DataTemplate>
可以只创建一个转换器,它将包含所有转换逻辑并返回一个您将绑定到的新类:
public class MyNewConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
// Perform all required conversions here and return them as a new type of object
return new
{
Data = ...,
Fill = ...,
Stroke = ...
};
}
}
那么你所需要做的就是修改你的Path
的DataContext
属性来使用这个转换器。
<Viewbox MaxHeight="20" HorizontalAlignment="Left" Cursor="Hand">
<WrapPanel>
<Path Margin="2,2,2,2" StrokeThickness="2" DataContext="{Binding Path=Status, Converter={StaticResource MyNewConverter}}">
<Path.Data>
<Binding Path="Data" Mode="OneWay" />
</Path.Data>
<Path.Fill>
<Binding Path="Fill" Mode="OneWay" />
</Path.Fill>
<Path.Stroke>
<Binding Path="Stroke" Mode="OneWay" />
</Path.Stroke>
</Path>
<ContentPresenter Content="{Binding Path=Name}" Margin="5,0,0,0" />
</WrapPanel>
</Viewbox>