我是
WPF和MVVM的新手.我认为这是一个简单的问题.我的viewmodel正在执行一个异步调用,以获取DataGrid的数据,该DataGrid绑定到viewmodel中的一个ObservableCollection.加载数据时,我设置了适当的viewmodel属性,DataGrid显示数据没有问题.但是,我想为用户介绍数据加载的视觉提示.所以,使用Blend,我把它添加到我的标记:
<VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="LoadingStateGroup"> <VisualState x:Name="HistoryLoading"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="HistoryGrid"> <DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Hidden}"/> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> <VisualState x:Name="HistoryLoaded"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="WorkingStackPanel"> <DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Hidden}"/> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups>
我想我知道如何改变我的代码隐藏状态(类似于此):
VisualStateManager.GoToElementState(LayoutRoot,"HistoryLoaded",true);
但是,我想要做的这个方面是在我的viewmodel的I / O完成方法中,它没有引用它的相应视图.我将如何使用MVVM模式来实现?
解决方法
你可以这样做:
XAML
<Window x:Class="WpfSOTest.BusyWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WpfSOTest" Title="BusyWindow" Height="300" Width="300"> <Window.Resources> <local:VisibilityConverter x:Key="VisibilityConverter" /> </Window.Resources> <Grid> <Grid.RowDefinitions> <RowDefinition /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <Border Grid.Row="0"> <Grid> <Border> <Rectangle Width="400" Height="400" Fill="#EEE" /> </Border> <Border Visibility="{Binding IsBusy,Converter={StaticResource VisibilityConverter}}"> <Grid> <Rectangle Width="400" Height="400" Fill="#AAA" /> <TextBlock Text="Busy" HorizontalAlignment="Center" VerticalAlignment="Center" /> </Grid> </Border> </Grid> </Border> <Border Grid.Row="1"> <Button Click="ChangeVisualState">Change Visual State</Button> </Border> </Grid>
码:
public partial class BusyWindow : Window { viewmodel viewmodel = new viewmodel(); public BusyWindow() { InitializeComponent(); DataContext = viewmodel; } private void ChangeVisualState(object sender,RoutedEventArgs e) { viewmodel.IsBusy = !viewmodel.IsBusy; } } public class viewmodel : INotifyPropertyChanged { protected Boolean _isBusy; public Boolean IsBusy { get { return _isBusy; } set { _isBusy = value; RaisePropertyChanged("IsBusy"); } } public viewmodel() { IsBusy = false; } public event PropertyChangedEventHandler PropertyChanged; public void RaisePropertyChanged(String propertyName) { PropertyChangedEventHandler temp = PropertyChanged; if (temp != null) { temp(this,new PropertyChangedEventArgs(propertyName)); } } } class VisibilityConverter : IValueConverter { public object Convert(object value,Type targetType,object parameter,System.Globalization.CultureInfo culture) { switch (((Boolean)value)) { case true: return Visibility.Visible; } return Visibility.Collapsed; } public object ConvertBack(object value,System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } }
———————–更新代码———————–
XAML
<Grid> <Grid.RowDefinitions> <RowDefinition /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <Border Grid.Row="0"> <Grid> <local:MyBorder IsBusy="{Binding IsBusy}"> <Grid> <TextBlock Text="{Binding IsBusy}" HorizontalAlignment="Center" VerticalAlignment="Center" /> </Grid> </local:MyBorder> </Grid> </Border> <Border Grid.Row="1"> <Button Click="ChangeVisualState">Change Visual State</Button> </Border> </Grid>
模板
<Style TargetType="{x:Type local:MyBorder}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type local:MyBorder}"> <Border Name="RootBorder"> <Border.Background> <SolidColorBrush x:Name="NormalBrush" Color="Transparent" /> </Border.Background> <VisualStateManager.VisualStateGroups> <VisualStateGroup Name="CommonGroups"> <VisualState Name="Normal" /> </VisualStateGroup> <VisualStateGroup Name="CustomGroups"> <VisualState Name="Busy"> <VisualState.Storyboard> <Storyboard> <ColorAnimation Storyboard.TargetName="NormalBrush" Storyboard.TargetProperty="Color" Duration="0:0:0.5" AutoReverse="True" RepeatBehavior="Forever" To="#EEE" /> </Storyboard> </VisualState.Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <ContentPresenter /> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style>
自定义元素
[TemplateVisualState(GroupName = "CustomGroups",Name = "Busy")] public class MyBorder : ContentControl { static MyBorder() { DefaultStyleKeyProperty.OverrideMetadata(typeof(MyBorder),new FrameworkPropertyMetadata(typeof(MyBorder))); } public Boolean IsBusy { get { return (Boolean)GetValue(IsBusyProperty); } set { SetValue(IsBusyProperty,value); } } public static readonly DependencyProperty IsBusyProperty = DependencyProperty.Register("IsBusy",typeof(Boolean),typeof(MyBorder),new UIPropertyMetadata(IsBusyPropertyChangedCallback)); static void IsBusyPropertyChangedCallback(DependencyObject d,DependencyPropertyChangedEventArgs e) { (d as MyBorder).OnIsBusyPropertyChanged(d,e); } private void OnIsBusyPropertyChanged(DependencyObject d,DependencyPropertyChangedEventArgs e) { if (Convert.ToBoolean(e.NewValue)) { VisualStateManager.GoToState(this,"Busy",true); } else { VisualStateManager.GoToState(this,"Normal",true); } } }