Интересная привязка ContentControl
Прежде всего, я должен сказать, что я начинающий программист, и вся помощь приветствуется. В настоящее время я работаю над приложением wpf, в котором я хотел бы иметь usercontrol с меткой и contentcontrol, который можно обновлять в зависимости от того, какая кнопка выбрана в окне приветствия. вот так
<Window x:Class="ContentControl.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:ContentControl.ViewModels"
xmlns:views="clr-namespace:ContentControl.Views"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<DataTemplate DataType="{x:Type vm:ScreenViewModel}">
<views:ScreenView DataContext="{Binding}"/>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:WelcomeViewModel}">
<views:WelcomeView DataContext="{Binding}"/>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:MeetingRoomViewModel}">
<views:MeetingRoomView DataContext="{Binding}"/>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:DashboardViewModel}">
<views:DashboardView />
</DataTemplate>
</Window.Resources>
<Grid>
<StackPanel>
<Label>This Is My Label</Label>
<ContentControl x:Name="MainPanel" Content="{Binding Path=Content}"
MinHeight="200"
MinWidth="200"
HorizontalContentAlignment="Left"
VerticalContentAlignment="Center"
Focusable="False">
</ContentControl>
</StackPanel>
</Grid>
</Window>
КОД позади:
public MainWindow()
{
InitializeComponent();
DataContext = this;
MainPanel.Content = new WelcomeView();
MainPanel.Content = this.MainPanel.Content;
}
}
Вот WelcomeViewModel:
internal class WelcomeViewModel : BaseViewModel
{
private MainWindowViewModel _mainWindowVm;
private RelayCommand<string> _viewChangedCommand;
public ICommand ViewChangedCommand
{
get { return _viewChangedCommand ?? (_viewChangedCommand = new RelayCommand<string>(OnViewChanged)); }
}
public event EventHandler ViewChanged;
private void OnViewChanged(string view)
{
EventHandler handler = ViewChanged;
if (handler != null) handler(view, EventArgs.Empty);
}
public MainWindowViewModel MainWindowVm
{
get { return _mainWindowVm; }
set
{
_mainWindowVm = value;
OnPropertyChanged("MainViewModel");
}
}
public WelcomeViewModel()
{
MainWindowVm = new MainWindowViewModel();
ViewChanged += MainWindowVm.ViewChanged;
}
}
И, наконец, мой welcome.xaml
<UserControl x:Class="ContentControl.Views.WelcomeView"
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:vm="clr-namespace:ContentControl.ViewModels"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.DataContext>
<vm:WelcomeViewModel />
</UserControl.DataContext>
<Grid Background="red">
<Grid.RowDefinitions >
<RowDefinition Height="25*" />
<RowDefinition Height="50*"/>
<RowDefinition Height="25*"/>
</Grid.RowDefinitions>
<Rectangle Grid.Row="0" Fill="Green"/>
<DockPanel Grid.Row="1" HorizontalAlignment="Center" Background="White">
<Button Height="50" Width="50" Margin="5" Content="DASH" Command="{Binding ViewChangedCommand}" CommandParameter="Dashboard"/>
<Button Height="50" Width="50" Margin="5" Content="ROOM" Command="{Binding ViewChangedCommand}" CommandParameter="MeetingRoom"/>
<Button Height="50" Width="50" Margin="5" Content="SCREEN" Command="{Binding ViewChangedCommand}" CommandParameter="Screen" />
</DockPanel>
<Rectangle Grid.Row="2" Fill="Blue"/>
</Grid>
</UserControl>
Таким образом, проблема заключается в том, что когда событие ViewChange запускается, оно отображается в MainWindowViewModel, однако, когда оно использует PropertyEventHandler(как показано ниже), PropertyChanged всегда имеет значение null.
public class BaseViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
}
2 ответа
Ну, здесь у вас есть некоторые ошибки WPF, Bindings и Mvvm... Во-первых, почему вы делаете это:
MainPanel.Content = this.MainPanel.Content;
это так же, как:
MainPanel.Content = MainPanel.Content;
эта линия неуместна.
Во-вторых, почему вы сказали:
Content="{Binding Path=Content}"
но затем вы устанавливаете в своем коде:
MainPanel.Content = new WelcomeView();
Здесь может возникнуть концептуальная ошибка: когда вы устанавливаете привязку по умолчанию, эта привязка будет сделана для DataContext самого элемента управления (в данном случае UserControl). Хорошо, чтобы решить эту проблему и работать с Mvvm, давайте сохраним привязку:
Content="{Binding Path=Content}"
Но теперь нам нужно установить текстовый код UserControl:
MainPanel.DataContext = new MainPanelViewModel();
И теперь нам нужно создать свойство в MainPanelViewModel с именем Content. Внутри этого свойства вы установите контент, который вы хотите показывать в ContentControl.Content. (В этом случае WelcomeViewModel и все, что вы хотите)
Надеюсь, этот ответ поможет вам начать с wpf и mvvm. это отличная платформа.
Хорошо. Ошибки, которые вы могли бы исправить:
- Не изменяйте MainPanel.Content в коде позади. Это должно быть изменено в ViewModel через связывание.
- В вашем Window.Resources обратите внимание, что вы устанавливаете DataContext в MainViewModel для WelcomeView, а в WelcomeView вы хотите, чтобы он был WelcomeIewModel. Это не работает так. DataCOntext=WelcomeViewModel переопределяется Window.Resources
- почему вы создаете новую MainViewmodel в WelcomeViewModel?
- PropertyChanged имеет значение null, поскольку вы не используете его в представлении (конкретном экземпляре MainiewMOdel). Если вы собираетесь связать его, PropertyChanged получит новый прослушиватель событий и больше не будет нулевым.
Возможно, объясните вашу проблему немного лучше, и я могу дать дополнительную информацию.