【WPF】MVVM动态修改Bingding的另一种思路——用Style样式

简介: 原文:【WPF】MVVM动态修改Bingding的另一种思路——用Style样式 问题场景: 界面上有个ListBox控件,它的内容Item绑定了一个列表,即 ItemsSource =”{Binding StudentList}”。
原文: 【WPF】MVVM动态修改Bingding的另一种思路——用Style样式

问题场景:
界面上有个ListBox控件,它的内容Item绑定了一个列表,即 ItemsSource =”{Binding StudentList}”。这个StudentList列表在该界面View对应的ViewModel中赋值。ListBox中每个元素Item都是一个Student实体类对象,核心代码如下:

View:

<ListBox 
    x:Name="studentLB" Margin="0" 
    VerticalAlignment="Top"
    HorizontalAlignment="Left"
    HorizontalContentAlignment="Stretch"
    ScrollViewer.CanContentScroll="False"
    ScrollViewer.HorizontalScrollBarVisibility="Disabled"
    ScrollViewer.VerticalScrollBarVisibility="Visible"
    ItemsSource="{Binding StudentList}">

     <!-- 流式布局,左对齐 -->
     <ListBox.ItemsPanel>
         <ItemsPanelTemplate>
             <WrapPanel HorizontalAlignment="Left"/>
         </ItemsPanelTemplate>
     </ListBox.ItemsPanel>

    <!-- 条目的模板 -->
    <ListBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Bingding FirstName}" />
        </DataTemplate>
    </ListBox.ItemTemplate>

</ListBox>

ViewModel:

private ObservableCollection<Student> studentList;
public ObservableCollection<Student> StudentList    // 前台ListBox的ItemsSource绑定该列表
{
    get { return studentList; }
    set { SetProperty(ref studentList, value); }
}

Student.cs实体类

public Class Student
{
    public int Id { get; set; } // 唯一标识符
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

需求:现在条目中TextBlock 绑定的是Student对象的FirstName属性,如何将其改为绑定到LastName属性?

思路:

  • 思路一:
    由于ItemsSource绑定到ViewModel中的StudentList列表,在Controller层从服务端获取到列表数据后,先进行加工,再赋值给StudentList。如先用一个临时列表TempList记录服务端返回的数据,然后遍历并修改该列表中的内容,想修改后的内容赋值给StudentList,如下:

// 由于前台TextBlock绑定的是FirstName属性,现将FirstName的值改为LastName的值,即保持前台绑定不变的情况下,动态修改被绑定的属性的值。
foreach(Student item in TempList)
{
    //sourceList是从服务端获取的列表数据
    foreach(Student source in SourceList) 
    {
        if (item.id == source.id)
        {
            item.FirstName = source.LastName;
        }
    }
}

经过测试,虽然数据层的确发生了改变,但显示层却并没有更新。说好的MVVM呢?怎么会数据变了不自动更新界面的??

  • 思路二:
    将ListBox的界面改为采用Style样式,准备两种样式,区别仅在于TextBlock绑定到的是FirstName还是LastName。在Controller层动态修改ListBox使用的样式!如可以用一个按钮,每次点击都来回切换这两种样式。

新建样式文件StudentStyle.xaml:

<!-- ListBox样式 切换显示学生的FirstName/LastName -->
<!-- 这两种样式仅有ListBoxItem中的TextBlock绑定到FirstName/LastName的不同 -->

<ResourceDictionary  x:Class="YourProjectName.Presentation.Style.ListBox_StudentStyle"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008">

    <!-- 样式1:显示FirstName -->
    <Style x:Key="firstNameStyle" TargetType="{x:Type ListBox}">
        <Setter Property="Margin" Value="0"/>
        <Setter Property="ItemsSource" Value="{Binding SpacePlansList}"/>
        <Setter Property="BorderThickness" Value="0"/>
        <Setter Property="VerticalAlignment" Value="Top"/>
        <Setter Property="HorizontalAlignment" Value="Left"/>
        <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
        <Setter Property="ScrollViewer.CanContentScroll" Value="False"/>
        <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled"/>
        <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Visible"/>

        <!-- 流式布局 左对齐 -->
        <Setter Property="ListBox.ItemsPanel">
            <Setter.Value>
                <ItemsPanelTemplate>
                    <WrapPanel HorizontalAlignment="Left"/>
                </ItemsPanelTemplate>
            </Setter.Value>
        </Setter>

        <Setter Property="ListBox.ItemTemplate">
              <Setter.Value>
                  <DataTemplate>
                      <TextBlock Text="{Binding FirstName}"/>
                  </DataTemplate>
              </Setter.Value>
          </Setter>
      </Style>

      <!-- 样式2:显示LastName -->
      <Style x:Key="lastNameStyle" TargetType="{x:Type ListBox}">
          <Setter Property="Margin" Value="0"/>
          <Setter Property="ItemsSource" Value="{Binding SpacePlansList}"/>
          <Setter Property="BorderThickness" Value="0"/>
          <Setter Property="VerticalAlignment" Value="Top"/>
          <Setter Property="HorizontalAlignment" Value="Left"/>
          <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
          <Setter Property="ScrollViewer.CanContentScroll" Value="False"/>
          <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled"/>
          <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Visible"/>

          <!-- 流式布局 左对齐 -->
          <Setter Property="ListBox.ItemsPanel">
              <Setter.Value>
                  <ItemsPanelTemplate>
                      <WrapPanel HorizontalAlignment="Left"/>
                  </ItemsPanelTemplate>
              </Setter.Value>
          </Setter>

          <Setter Property="ListBox.ItemTemplate">
              <Setter.Value>
                  <DataTemplate>
                      <TextBlock Text="{Binding LastName}"/>
                  </DataTemplate>
              </Setter.Value>
          </Setter>
      </Style>

</ResourceDictionary>

View:

<!-- 引入样式资源 -->
<UserControl.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="/Presentation/Style/ListBox_StudentStyle.xaml" />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</UserControl.Resources>

<!-- 使用样式,默认使用显示FirstName的样式 -->
<ListBox x:Name="studentLB" Style="{StaticResource firstNameStyle}"/>

控制层动态修改ListBox的样式:

private Style listbox_FirstNameSytle;   // 显示FirstName的样式
private Style listbox_LastNameSytle;    // 显示LastName的样式

// 在控制层的初始化方法中,获取这两种样式
public void Initialize()
{
    var listBoxStyle = new ResourceDictionary
    {
        Source = new Uri("/YourProjectName;component/Presentation/Style/ListBox_StudentStyle.xaml", UriKind.RelativeOrAbsolute) // 指定样式文件的路径
    };

    listbox_FirstNameSytle = listBoxStyle["firstNameStyle"] as Style;
    listbox_LastNameSytle = listBoxStyle["lastNameStyle"] as Style;
}

private void btn_Click(object sender, RoutedEventArgs e)
{
    // 根据按钮的状态,切换ListBox的样式
    if (view.btn.IsChecked == true)
    {
        view.studentLB.Sytle = listbox_LastNameSytle;
    }
    else
    {
        view.studentLB.Sytle = listbox_FirstNameSytle;
    }
}

经测试,该方法可行!


小结:

准备多套样式,通过动态修改样式来实现类似于动态修改绑定的效果。

目录
相关文章
WPF疑难问题之Treeview中HierarchicalDataTemplate多级样式
WPF疑难问题之Treeview中HierarchicalDataTemplate多级样式
343 0
|
2月前
|
设计模式 前端开发 C#
WPF 项目中 MVVM模式 的简单例子说明
本文通过WPF项目中的加法操作示例,讲解了MVVM模式的结构和实现方法,包括数据模型、视图、视图模型的创建和数据绑定,以及命令的实现和事件通知机制。
|
3月前
|
前端开发 C# 设计模式
“深度剖析WPF开发中的设计模式应用:以MVVM为核心,手把手教你重构代码结构,实现软件工程的最佳实践与高效协作”
【8月更文挑战第31天】设计模式是在软件工程中解决常见问题的成熟方案。在WPF开发中,合理应用如MVC、MVVM及工厂模式等能显著提升代码质量和可维护性。本文通过具体案例,详细解析了这些模式的实际应用,特别是MVVM模式如何通过分离UI逻辑与业务逻辑,实现视图与模型的松耦合,从而优化代码结构并提高开发效率。通过示例代码展示了从模型定义、视图模型管理到视图展示的全过程,帮助读者更好地理解并应用这些模式。
94 0
|
3月前
|
开发者 C# 存储
WPF开发者必读:资源字典应用秘籍,轻松实现样式与模板共享,让你的WPF应用更上一层楼!
【8月更文挑战第31天】在WPF开发中,资源字典是一种强大的工具,用于共享样式、模板、图像等资源,提高了应用的可维护性和可扩展性。本文介绍了资源字典的基础知识、创建方法及最佳实践,并通过示例展示了如何在项目中有效利用资源字典,实现资源的重用和动态绑定。
73 0
|
3月前
|
前端开发 开发者 C#
WPF开发者必读:MVVM模式实战,轻松实现现代桌面应用架构,让你的代码更上一层楼!
【8月更文挑战第31天】在WPF应用程序开发中,MVVM(Model-View-ViewModel)模式通过分离应用程序的逻辑和界面,提高了代码的可维护性和可扩展性。本文介绍了MVVM模式的三个核心组件:Model(数据模型)、View(用户界面)和ViewModel(处理数据绑定和逻辑),并通过示例代码展示了如何在WPF项目中实现MVVM模式。通过这种方式,开发者可以构建更加高效和可扩展的桌面应用程序。
153 0
|
3月前
|
前端开发 C# 开发者
WPF开发者必读:MVVM模式实战,轻松构建可维护的应用程序,让你的代码更上一层楼!
【8月更文挑战第31天】在WPF应用程序开发中,MVVM(Model-View-ViewModel)模式通过分离关注点,提高了代码的可维护性和可扩展性。本文详细介绍了MVVM模式的三个核心组件:Model(数据模型)、View(用户界面)和ViewModel(处理数据绑定与逻辑),并通过示例代码展示了如何在WPF项目中实现MVVM模式。通过这种模式,开发者可以更高效地构建桌面应用程序。希望本文能帮助你在WPF开发中更好地应用MVVM模式。
168 0
|
3月前
|
开发者 C# 存储
WPF开发者必读:样式与模板的艺术,轻松定制UI外观,让你的应用程序更上一层楼!
【8月更文挑战第31天】在WPF应用开发中,样式与模板是实现美观界面与一致性的关键工具。样式定义了控件如字体、颜色等属性,而模板则允许自定义控件布局与子控件,两者均可存储于`.xaml`文件中。本文介绍了样式与模板的基础知识,通过示例展示了如何创建并应用它们来改变按钮的外观,从而提升用户体验。
70 0
|
3月前
|
存储 前端开发 C#
WPF/C#:更改界面的样式
WPF/C#:更改界面的样式
41 0
|
3月前
|
设计模式 前端开发 C#
WPF/C#:理解与实现WPF中的MVVM模式
WPF/C#:理解与实现WPF中的MVVM模式
161 0
WPF-布局样式练习-Day02-聊天气泡
WPF-布局样式练习-Day02-聊天气泡
236 1