Подскажите, пожалуйста, как можно реализовать большое количество кнопок с одинаковыми двумя изменяющимися картинками так, чтобы не писать для каждой кнопки свойство и команду(автоматизация, так сказать).И желательно, чтоб соблюдался MVVM.
Пример кода
Разметка XAML:
<Window x:Class="TestWPF.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:TestWPF"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<Style x:Key="image">
<Style.Triggers>
<DataTrigger Binding="{Binding IsFirstImage}" Value="False">
<Setter Property="Image.Source" Value="Resources/image1.png" />
</DataTrigger>
<DataTrigger Binding="{Binding IsFirstImage}" Value="True">
<Setter Property="Image.Source" Value="Resources/image2.png" />
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Border>
<Canvas>
<Button x:Name="button1" Width="41" Height="38" Opacity="1" Command="{Binding ToggleCommand}" Canvas.Left="150" Canvas.Top="146">
<Image x:Name="Qwe1" Style="{StaticResource ResourceKey=image}" Width="41" Height="37"/>
</Button>
<Button x:Name="button2" Width="41" Height="38" Opacity="1" Command="{Binding ToggleCommand}" Canvas.Left="100" Canvas.Top="146">
<Image x:Name="Qwe2" Style="{StaticResource ResourceKey=image}" Width="41" Height="37"/>
</Button>
<Button x:Name="button3" Width="41" Height="38" Opacity="1" Command="{Binding ToggleCommand}" Canvas.Left="200" Canvas.Top="146">
<Image x:Name="Qwe3" Style="{StaticResource ResourceKey=image}" Width="41" Height="37"/>
</Button>
</Canvas>
</Border>
</Window>
И моя VM:
namespace TestWPF
{
class ViewModel : INotifyPropertyChanged
{
private bool isFirstImage;
public bool IsFirstImage
{
get { return isFirstImage; }
set { isFirstImage = value; OnPropertyChanged("IsFirstImage"); }
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName]string prop = "")
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(prop));
}
private RelayCommand toggleCommand;
public RelayCommand ToggleCommand
{
get
{
return toggleCommand ??
(toggleCommand = new RelayCommand(obj =>
{
IsFirstImage = !IsFirstImage;
}));
}
}
}
}
Вот у меня три кнопки, все три кнопки изначально при запуске приложения имеют image1, нужно, чтобы при нажатии на определенную кнопку менялась картинка этой же кнопки, на которую нажал (в данный момент у меня при нажатии на любую кнопку меняются картинки на всех кнопках одновременно, оно и понятно, ведь биндинг к одному и тому же свойству). Подскажите, как написать грамотней код, чтобы к каждой кнопке не прописывать отдельное свойство и отдельную команду. Ведь будет неудобно писать для 100 кнопок 100 свойств, 100 команд и 100 привязок в разметке.
BindingList
или ObservableCollection
, ибо они имеют реализацию INotifyCollectionChanged
.Исходя из этого вы можете сделать следующее:
Создаем коллекцию:
public ObservableCollection<ViewModel> Items { get; }
ViewModel
- это ваш класс со свойствами для кнопки.
get;
- нам по сути надо получить только из нее элементы, не инициализируя ее постоянно, по этому тут нет set;
.
Инициализируем коллекцию и заполняем.
public MainViewModel()
{
Items = new ObservableCollection<ViewModel>
{
new ViewModel() //Задаем нужные свойства если надо.
};
}
Вы в любой момент можете написать Items.Add(...)
.
Переделываем XAML:
Меняем
<Canvas>
<Button x:Name="button1" Width="41" Height="38" Opacity="1" Command="{Binding ToggleCommand}" Canvas.Left="150" Canvas.Top="146">
<Image x:Name="Qwe1" Style="{StaticResource ResourceKey=image}" Width="41" Height="37"/>
</Button>
<Button x:Name="button2" Width="41" Height="38" Opacity="1" Command="{Binding ToggleCommand}" Canvas.Left="100" Canvas.Top="146">
<Image x:Name="Qwe2" Style="{StaticResource ResourceKey=image}" Width="41" Height="37"/>
</Button>
<Button x:Name="button3" Width="41" Height="38" Opacity="1" Command="{Binding ToggleCommand}" Canvas.Left="200" Canvas.Top="146">
<Image x:Name="Qwe3" Style="{StaticResource ResourceKey=image}" Width="41" Height="37"/>
</Button>
</Canvas>
На
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Width="41" Height="38" Command="{Binding ToggleCommand}">
<Image Style="{StaticResource ResourceKey=image}" Width="41" Height="37"/>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Тут как видите все лишнее убрано, используется ItemsControl
, который привязан к коллекции Items
. В качестве ItemsPanel
задан WrapPanel
(тут смотрите сами, как кнопки будут размещаться). Также переопределен шаблон ItemTemplate
, в него переехала ваша кнопка.
Вот собственно и все, у вас должно будет вывести всю коллекцию Items
с заданным шаблоном.
P.S. Код писал на коленке, так что могут быть неточности.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Я бы хотел увидеть пример реализации для любой пользовательской структуры
Я делаю свечение через DropShadowEffectЕсли тупо повесить его на прогресс бар, свечение будет на всем прогресс баре
Есть форма, которая делает api запрос через таймерМне нужно запустить несколько таких форм, чтобы они делали api запрос
У меня есть несколько девайсовПрограмма должно эти устройства постоянно пинговать