#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?: