簡體   English   中英

控件可見性與ViewModel屬性的綁定不起作用

[英]Binding of control visibility to ViewModel property doesn't work

我正在將相當大的WPF應用程序從三層轉換為MVVM,並且正在學習MVVM。 到目前為止,我還沒有深入研究Bindings(等)的細節,所以請耐心等待。

我試圖將多個控件的System.Windows.Visibility綁定到ViewModel的公共屬性(“狀態”)。 加載父TabItem時,將根據需要讀取和處理State屬性。 但是,當對該屬性進行后續更改時,它們似乎被忽略了。 我已經(重新-重新-)檢查了綁定,調試了轉換器,等等,這讓我發瘋了。

視圖模型:

public class MarketingListViewModel: IDisposable, INotifyPropertyChanged
{
    private UiState state;

    public event PropertyChangedEventHandler PropertyChanged;
    public UiState State 
    {
        get { return state; }
        set
        {
            if (state != value)
            {
                state = value;
                NotifyPropertyChanged("State");
            }
        }
    }

    public MarketingListViewModel() 
    {
        State = UiState.View;
    }

    private void NotifyPropertyChanged(String info) 
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }

}

視圖:

<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
         mc:Ignorable="d" x:Class="WpfCrm.tabListManager" xmlns:DPH="clr-namespace:DPH" >

<UserControl.Resources>
    <DPH:MarketingListViewModel x:Key="listVM" />
    <!-- Note that the above line is giving me an "Object reference not set to an instance of an object" error -->
</UserControl.Resources>

<Grid x:Name="gridMain" DataContext="{StaticResource listVM}" >

    <Border Grid.Row="0" Grid.Column="1" Margin="10"
            Style="{StaticResource WidgetStyle}" >
        <Grid x:Name="gridListManagement" >
            <Label x:Name="labelManageLists" Content="Manage Lists" MouseDown="labelManageLists_MouseDown"
                Style="{StaticResource WidgetTitleStyle}"
                Grid.Row="0" Grid.Column="0" />

            <StackPanel Grid.Row="0" Grid.Column="2" Orientation="Horizontal"  HorizontalAlignment="Right" >
                <Label x:Name="llNewList" Content="new" MouseDown="llNewList_MouseDown"
                    Style="{StaticResource LinkLabelStyle}"
                    HorizontalAlignment="Right" />
                <Label x:Name="llCloseManageLists" Content="close" MouseDown="llCloseManageLists_MouseDown" 
                    Style="{StaticResource LinkLabelStyle}"
                    HorizontalAlignment="Right" />
            </StackPanel>

            <Label x:Name="labelListName" Content="Name" Grid.Row="1" Grid.Column="0" />
            <Grid Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2" HorizontalAlignment="Stretch" >
                <ComboBox x:Name="cbLists" SelectedIndex="-1" SelectionChanged="cbLists_SelectionChanged" IsReadOnly="True"
                          ItemsSource="{Binding Path=AllMarketingLists}" 
                          DisplayMemberPath="Name" 
                          SelectedValuePath="Id"
                          Visibility="{Binding Path=State, Converter={StaticResource ViewStateToVisibilityConverter} }"/>
                <TextBox x:Name="tbListName" 
                         Text="{Binding Path=OList.Name}"
                         Visibility="{Binding Path=State, Converter={StaticResource EditStateToVisibilityConverter} }"/>
            </Grid>

            <Label x:Name="labelListDescription" Content="Description" Grid.Row="2" Grid.Column="0" />
            <Grid Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="2" >
                <TextBlock x:Name="textblockListDescription" TextWrapping="Wrap" 
                           Text="{Binding Path=OList.Notes}"
                           Visibility="{Binding Path=State, Converter={StaticResource ViewStateToVisibilityConverter} }"
                           Grid.ColumnSpan="2" />
                <TextBox x:Name="tbListDescription" TextWrapping="Wrap"
                         Text="{Binding Path=OList.Notes}"
                         Visibility="{Binding Path=State, Converter={StaticResource EditStateToVisibilityConverter} }"
                         Grid.ColumnSpan="2" />
            </Grid>

            <StackPanel Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="3" HorizontalAlignment="Right" Orientation="Horizontal" >
                <Button x:Name="buttonEditList" Content="Edit" Click="buttonEditList_Click"
                        Visibility="{Binding Path=State, Converter={StaticResource ViewStateToVisibilityConverter} }"
                        Width="60" Margin="3" />
                <Button x:Name="buttonSaveList" Content="Save" Click="buttonSaveList_Click"
                        Visibility="{Binding Path=State, Converter={StaticResource EditStateToVisibilityConverter} }"
                        Width="60" Margin="3" />
                <Button x:Name="buttonCancel" Content="Cancel" Click="buttonCancel_Click" 
                        Visibility="{Binding Path=State, Converter={StaticResource EditStateToVisibilityConverter} }"
                        Width="60" Margin="3" />
            </StackPanel>

        </Grid>
    </Border>

</Grid>

后面的代碼有幾種方法,例如:

    private void buttonEditList_Click(object sender, RoutedEventArgs e) 
    {
        listVM.State = UiState.Edit;
    }

有人對州變更后控件為什么不更新其可見性有任何想法嗎?

謝謝,

DPH

編輯-轉換器:

[ValueConversion(typeof(WpfCrm.UiState), typeof(System.Windows.Visibility))]
public class EditStateToVisibilityConverter: IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        UiState state = (UiState)value;
        if (state == UiState.View) return Visibility.Collapsed;
        else return Visibility.Visible;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return null;
    }
}

[ValueConversion(typeof(WpfCrm.UiState), typeof(System.Windows.Visibility))]
public class ViewStateToVisibilityConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        UiState state = (UiState)value;
        if (state == UiState.View) return Visibility.Visible;
        else return Visibility.Collapsed;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return null;
    }
}

您似乎使用了視圖模型的兩個不同實例,其中一個在XAML中聲明並使用過。

<UserControl.Resources>
    <DPH:MarketingListViewModel x:Key="listVM" />
</UserControl.Resources>
<Grid DataContext="{StaticResource listVM}" >

和一個在代碼后面(來自注釋):

listVM = new MarketingListViewModel(); 

您當然應該只使用一個。 因此,將聲明后的代碼更改為

listVM = (MarketingListViewModel)Resources["listVM"]; 

好,有一個錯誤。 您將listVM聲明為

var listVM = new MarketingListViewModel();

但這不是XAML中的listVM。 在XAML中,您創建了MarketingListViewModel的另一個實例。 因此,當您嘗試更改在代碼中聲明的listVM時,什么也不會發生,因為此對象不是Grid的DataContext。

在您的Click處理程序中,您必須編寫以下內容:

private void buttonEditList_Click(object sender, RoutedEventArgs e) 
{
    var _listVM = (MarketingListViewModel)FindResource("listVM");
    _listVM.State = UiState.Edit;
}

或用以下代碼替換代碼中的listVM聲明:

listVM = (MarketingListViewModel)FindResource("listVM");

然后,您無需更改事件處理程序。

希望能幫助到你。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM