相手の発言が左、自分の発言が右に来るようにListBoxのStyleを動的に変更しようとしました。
正確にはListBox
のItemContainerStyle
で、ListBoxItem
のStyle
をDataTrigger
で変えるということですね?
DataTriggerのValueはバインドできませんでした。(Bindingは使えないというエラーメッセージ)
できなかったことも「試したこと」として提示いただけると、やりたいことがはっきりして回答しやすいです。
DynamicResourcesを使おうと思ったんですが、調べてもResoucesに単純なstringをバインドする方法が見つかりませんでした。
こういうことか自信がありませんが、回答コードにはコメントで入れた通り結論はダメでした。
※省略してあります
もちろん全部出されても困りますが、もう少しないとこちらで再現コードを書く手間と認識があっているかの確信が持てないです^^;
前置きが長すぎましたが質問について、「wpf datatrigger value binding」で検索したところ↓がヒットしました。
.net - Using binding for the Value property of DataTrigger condition - Stack Overflow
コンバータが必要なのがちょっと気になります^^;(ほかのアプローチも何かありそうですが
xml
1<Window
2 x:Class="Questions345940.MainWindow"
3 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
4 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
5 xmlns:local="clr-namespace:Questions345940"
6 xmlns:md="http://materialdesigninxaml.net/winfx/xaml/themes"
7 xmlns:sys="clr-namespace:System;assembly=mscorlib"
8 Width="400"
9 Height="600">
10 <Window.Resources>
11 <local:MultiValueEqualityConverter x:Key="multiValueEqualityConverter" />
12 <!--<sys:String x:Key="myname">dekaribon</sys:String>-->
13 </Window.Resources>
14 <Window.DataContext>
15 <local:DirectMessageViewModel />
16 </Window.DataContext>
17 <DockPanel>
18 <DockPanel DockPanel.Dock="Bottom">
19 <Button
20 Command="{Binding SendCommand}"
21 Content="send"
22 DockPanel.Dock="Right" />
23 <RadioButton
24 Content="dekaribon"
25 IsChecked="{Binding IsChecked.Value}"
26 Style="{StaticResource MaterialDesignChoiceChipRadioButton}" />
27 <RadioButton Content="TN8001" Style="{StaticResource MaterialDesignChoiceChipRadioButton}" />
28 <TextBox VerticalAlignment="Center" md:HintAssist.Hint="message" />
29 </DockPanel>
30
31 <ListBox md:ThemeAssist.Theme="Dark" ItemsSource="{Binding MessageInfos}">
32 <ListBox.ItemContainerStyle>
33 <Style BasedOn="{StaticResource MaterialDesignListBoxItem}" TargetType="ListBoxItem">
34 <Setter Property="HorizontalAlignment" Value="Left" />
35 <Style.Triggers>
36 <DataTrigger Value="True">
37 <DataTrigger.Binding>
38 <MultiBinding Converter="{StaticResource multiValueEqualityConverter}">
39 <Binding Path="Username" />
40 <Binding Path="DataContext.Account.Value.Username" RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type ListBox}}" />
41 </MultiBinding>
42 </DataTrigger.Binding>
43 <Setter Property="HorizontalAlignment" Value="Right" />
44 </DataTrigger>
45
46 <!-- XDG0062 'DynamicResourceExtension' は、有効なトリガーの条件ではありません。 -->
47 <!--<DataTrigger Binding="{Binding Username}" Value="{DynamicResource myname}">
48 <Setter Property="HorizontalAlignment" Value="Right" />
49 </DataTrigger>-->
50 </Style.Triggers>
51 </Style>
52 </ListBox.ItemContainerStyle>
53 <ListBox.ItemTemplate>
54 <DataTemplate>
55 <md:Card
56 Margin="2"
57 Padding="20"
58 md:ShadowAssist.ShadowDepth="Depth2">
59 <StackPanel>
60 <TextBlock HorizontalAlignment="Center" Text="{Binding Username}" />
61 <Separator Margin="2,5" />
62 <TextBlock Margin="10,0,0,0" Text="{Binding Message}" />
63 </StackPanel>
64 </md:Card>
65 </DataTemplate>
66 </ListBox.ItemTemplate>
67 </ListBox>
68 </DockPanel>
69</Window>
cs
1using Reactive.Bindings;
2using System;
3using System.Globalization;
4using System.Linq;
5using System.Windows;
6using System.Windows.Data;
7
8namespace Questions345940
9{
10 // [.net - Using binding for the Value property of DataTrigger condition - Stack Overflow](https://stackoverflow.com/questions/2240421/using-binding-for-the-value-property-of-datatrigger-condition)
11 public class MultiValueEqualityConverter : IMultiValueConverter
12 {
13 public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
14 => values?.All(o => o?.Equals(values[0]) == true) == true || values?.All(o => o == null) == true;
15 public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
16 => throw new NotImplementedException();
17 }
18
19 public class AccountData
20 {
21 public string Username { get; set; }
22 }
23
24 public class DirectMessageItem
25 {
26 public string Username { get; set; }
27 public string Message { get; set; }
28 }
29
30 public class DirectMessageViewModel
31 {
32 public ReactiveProperty<AccountData> Account { get; } = new();
33 public ReactiveCollection<DirectMessageItem> MessageInfos { get; } = new();
34 public ReactiveCommand<string> SendCommand { get; } = new();
35 public ReactiveProperty<bool> IsChecked { get; } = new(true);
36
37 public DirectMessageViewModel()
38 {
39 Account.Value = new() { Username = "dekaribon", };
40 MessageInfos.Add(new() { Username = "dekaribon", Message = "aaa", });
41 MessageInfos.Add(new() { Username = "TN8001", Message = "bbb", });
42
43 SendCommand.Subscribe(message =>
44 {
45 MessageInfos.Add(new()
46 {
47 Username = Account.Value.Username,
48 Message = message,
49 });
50 });
51
52 // アカウントチェンジ(不自然なチェンジだが、入れ替わりのテスト
53 IsChecked.Subscribe(x =>
54 {
55 Account.Value = x ? new() { Username = "dekaribon", }
56 : new() { Username = "TN8001", };
57 });
58 }
59 }
60
61 public partial class MainWindow : Window
62 {
63 public MainWindow() => InitializeComponent();
64 }
65}
以降は質問には関係ないんですが、コードを書いていて不思議に思ったことです。
あるSNSのアカウントごとにAPIを使用してダイレクトメッセージをLINE風に表示しようとしています。
AccountData.Usernameが自分のユーザー名、DirectMessageItem.Usernameが相手のユーザー名になります。
私が理解できていないだけかもしれませんが、逆じゃないですか?
「アカウントごと」というのは、DirectMessageViewModel
ごとという意味ですよね?
DirectMessageViewModel
のリストがあり、自分<->Aさん・自分<->Bさん等になるんですよね?
自分と相手しかいないのであれば、Account.Username
に自明な自分より相手の名前があったほうが便利そうですが(それとも最初から複垢想定?^^;
Account
がReactiveProperty
なのも「あれ?」と思いました。
変更される時があるということですかね?(DirectMessageViewModel
は一つで使いまわす設計?)
それを逆手にとって、回答コードは入れ替わりのテストができたのですが^^;
あとThemeAssist.Theme="Dark"
の当て方はあっているんでしょうか?
回答コードだとListBox
の選択が見えない(これは結果OKっぽい)のと、スクロールバーの色が見えなくなりました^^;
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/06/25 04:12