WPF привязывает элемент управления MainWindow из UserControl, PropertyChanged не запускается

#wpf #binding

#wpf #привязка

Вопрос:

Я новичок в WPF и столкнулся с проблемой, связанной с привязкой. У меня есть a MainWindow с a Rectangle , который использует привязку для изменения визуальных атрибутов. Код XAML выглядит следующим образом:

 <Rectangle Height="72" Canvas.Left="1011" RadiusY="6" RadiusX="6" StrokeThickness="2" Width="82" Canvas.Top="8">
    <Rectangle.Style>
        <Style TargetType="Rectangle">
            <Style.Triggers>
                <DataTrigger Binding="{Binding BddState}" Value="True">
                    <Setter Property="Fill">
                      <Setter.Value>
                        <ImageBrush ImageSource="Pictures/BDD_on.png" Stretch="Uniform" />
                      </Setter.Value>
                    </Setter>

                </DataTrigger>
                <DataTrigger Binding="{Binding BddState}" Value="False">
                    <Setter Property="Fill">
                        <Setter.Value>
                            <ImageBrush ImageSource="Pictures/Bdd_off.png" Stretch="Uniform" />
                        </Setter.Value>
                    </Setter>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Rectangle.Style>
</Rectangle>
 

Я создал класс модели представления для управления привязкой:

 public class ViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(String propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyName));
    }


    private Boolean _bddstate;
    public Boolean BddState
    {
        get { return _bddstate; }
        set
        {
            _bddstate = value;
            OnPropertyChanged("BddState");
        }
    }
}
 

Привязка хорошо работает из MainWindow с помощью:

 private ViewModel _viewModel = new ViewModel();

public MainWindow()
{
    InitializeComponent();
    this.DataContext = _viewModel;
    _viewModel.BddState = true;        
}
 

Внутри MainWindow я использую a StackPanel для загрузки другого UserControl ( MainWindow действует как заголовок).
Меня беспокоит привязка из UserControl ; значение BddState изменяется соответствующим образом, но ничего не отражается на MainWindow пользовательском интерфейсе.
В то же время я вижу, что обработчик модели представления всегда null .

Что я делаю не так?

Заранее спасибо за вашу поддержку.

Обновление: вот код пользовательского элемента управления:

 <Grid Background="#FFECECEC" Height="706" VerticalAlignment="Top">
    <Label x:Name="label" Content="HOME" HorizontalAlignment="Left" Margin="525,8,0,0" VerticalAlignment="Top" FontWeight="Bold" Foreground="{DynamicResource gray_2}" FontSize="20"/>
    <Label x:Name="label_Copy" Content="General Info" HorizontalAlignment="Left" Margin="441,34,0,0" VerticalAlignment="Top" Foreground="{DynamicResource gray_2}" FontSize="18"/>
    <Button x:Name="button" Content="Button" HorizontalAlignment="Left" Margin="441,214,0,0" VerticalAlignment="Top" Width="107" Height="36" Click="button_Click"/>


</Grid>
 

для кода, лежащего в основе, это просто следующее:

  public partial class Home : UserControl
{
    public Home()
    {
        InitializeComponent();
    }

    private void button_Click(object sender, RoutedEventArgs e)
    {
        ViewModel _vm = new ViewModel();
        _vm.BddState = true;
    }
}
 

Когда я нажимаю кнопку Home UC, обработчик ViewModel имеет значение null, и привязка не действует на прямоугольник MainWindow

вот некоторые обновления, следующие за примером Энди (это может помочь), путем приведения mainwindow datacontext, он работает:

  MainWindowViewModel viewModel = App.Current.MainWindow.DataContext as MainWindowViewModel;
        if (viewModel != null)
        {
            viewModel.BddState = true;
        }
 

Комментарии:

1. » Меня беспокоит привязка от UserControl » — где эти пользовательские элементы управления в вашем примере кода?

2. Для пользовательского элемента управления я пытался использовать:

3. ViewModel _vm = new ViewModel(); _vm.BddState = true;

4. Какой UserControl? В вашем вопросе его нет.

5. извините, я пропустил это. Я создал пользовательский элемент управления с именем «Спецификация». Я загружаю этот UC в стековую панель Mainwindow: (Stackpanel.children. Add(new Specification()); затем я пытаюсь изменить прямоугольное изображение из этого uc, используя приведенный выше код

Ответ №1:

Я изменил вашу разметку на:

     <Canvas Name="MyCanvas" >
        <Rectangle Height="72"  RadiusY="6" RadiusX="6" StrokeThickness="2" Width="82" Canvas.Top="8">
            <Rectangle.Style>
                <Style TargetType="Rectangle">
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding BddState}" Value="True">
                            <Setter Property="Fill" Value="Green"/>
                        </DataTrigger>
                        <DataTrigger Binding="{Binding BddState}" Value="False">
                            <Setter Property="Fill" Value="Yellow"/>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </Rectangle.Style>
        </Rectangle>
    </Canvas>
 

Который не зависит ни от какого изображения, ни от Canvas.Left.

Я получаю зеленый прямоугольник.

Возможные причины, по которым вы ничего не видите, включают:

Ваше окно уже, чем 1011 пикселей и холст.Left =»1011″ означает, что ваш прямоугольник не находится в вашем окне.

Ваши пути к изображениям не работают.

Равномерное растяжение создает проблему, и часть прямоугольника, в которой есть какое-либо изображение, находится за пределами экрана.

Затем я изменил это еще больше, чтобы изначально установить bddstate true через поле private backing в viewmodel. Добавлена кнопка переключения с привязкой ischecked к bddstate. Это успешно переключается между желтым и зеленым.

Вот рабочая версия, включающая usercontrol. Я унаследовал MainWindowViewModel от BaseViewModel, который у меня был в моем тестовом образце.

MainWindow:

  <Window.DataContext>
    <local:MainWindowViewModel/>
</Window.DataContext>
<Grid>
    <Canvas Name="MyCanvas" >
        <Rectangle Height="72"  RadiusY="6" RadiusX="6" StrokeThickness="2" Width="82" Canvas.Top="8">
            <Rectangle.Style>
                <Style TargetType="Rectangle">
                    <Setter Property="Fill" Value="Green"/>
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding BddState}" Value="False">
                            <Setter Property="Fill" Value="Yellow"/>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </Rectangle.Style>
        </Rectangle>
    </Canvas>
    <local:UserControl1 Height="30" Width="100"/>
</Grid>
 

Viewmodel:

 public class MainWindowViewModel : BaseViewModel
{
    private Boolean _bddstate = true;
    public Boolean BddState
    {
        get { return _bddstate; }
        set
        {
            _bddstate = value;
            RaisePropertyChanged("BddState");
        }
    }
 

UserControl1

     <ToggleButton Width="100" Height="30" Content="Toggle" IsChecked="{Binding BddState, Mode=TwoWay}"/>
 

BaseViewModel

 public  class BaseViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    protected void RaisePropertyChanged([CallerMemberName] String propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}
 

За этим нет кода.

И это все еще работает.

Комментарии:

1. Изображение можно увидеть, если изменение bddstate происходит из Mainwindows. Нет видимого эффекта, когда изменение bbstate происходит от другого пользовательского элемента управления. Проблема, похоже, связана с datacontext или чем-то в этом роде

2. Что произойдет, если ваша кнопка переключения находится в usercontrol (прямоугольник остается в MainWindow)?

3. Если usercontrol находится в окне, то datacontext является общим, потому что DataContext помечен как наследование (вниз по визуальному дереву). Это означает, что IsChecked этого переключателя все равно будет привязан к bddstate, и он все равно будет работать. Если вы сначала использовали viewmodel, чтобы пользовательский элемент управления был шаблонизирован, а datacontext пользовательского элемента управления отличается, тогда вам нужно будет использовать relativesource для перехода к DataContext.bddstate родительского окна.

4. Я добавил больше разметки с помощью кнопки переключения в usercontrol.

5. Я воспроизвел ваш образец, и он отлично работает с помощью кнопки переключения, как насчет изменения bbdstate из codebehind?: