作成日 | 2024/05/17 |
最終更新日 | 2025/06/04 |
動作は以下の通りです。
同じデータを参照するようにしてないのでそれぞれで画像を選択します。
閉じる処理を共通化してないのでそれぞれのwindowを閉じる必要があります。
とりあえず2つのwindowに共通のデータを入れようと思ったのでviewModelを使ってみます。同時に閉じるのはもう少し調べます。
画面に動きがあるとわかりやすいのでテキストボックスをおいてデータを反映できるようにします。
いくつかのサイト[2][3]を参考にしました。
画像を開くロジックを移動させるより、1から作ったほうが差分が小さそうなのでロジックを新規作成しました。実装したものは以下の通りです。
TestCommand.cs
namespace ImageTest { public class TestCommand : ICommand { private AppViewModel viewModel { get; set; } public TestCommand(AppViewModel viewModel) { this.viewModel = viewModel; } public event EventHandler? CanExecuteChanged { add { CommandManager.RequerySuggested += value; } remove { CommandManager.RequerySuggested -= value; } } public bool CanExecute(object? parameter) { return true; } public void Execute(object? parameter) { viewModel.Value += "a"; } } }
AppViewModel.cs
namespace ImageTest { public class AppViewModel : INotifyPropertyChanged { public event PropertyChangedEventHandler? PropertyChanged; private string test = ""; public TestCommand TestCommand { get; set; } public AppViewModel() { TestCommand = new TestCommand(this); } public string Value { get { return test; } set { test = value; if (PropertyChanged != null) { PropertyChanged( this, new PropertyChangedEventArgs("Value") ); } } } } }
Valueが変更されたことをviewに通知することでviewが最新の情報を参照できるようになります。 レイアウトもちょい修正しました。 以下のコードはmainWindowですが、SubWindowも同じ変更を加えます。
MainWindow.xml
<Grid> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition/> </Grid.ColumnDefinitions> <Grid> <Grid.RowDefinitions> <RowDefinition/> <RowDefinition/> <RowDefinition/> </Grid.RowDefinitions> <TextBox Grid.Row="0" Text="{Binding Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" /> <Button Grid.Row="1" Command="{Binding TestCommand}" > text change </Button> <Button Click="Button_Click" Grid.Row="2" > open dialog </Button> </Grid> <Image Grid.Column="1" x:Name="roadedImage" /> </Grid>
<TextBox
Grid.Row="0"
Text="{Binding Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
/>
viewModelを複数のwindowに紐づけます。複数windowを表示[1]を参考にしてwindowを複数表示するようにしたので、そのままapp.xml.csをベースにviewModelの紐づけを行います。stackOverFLowの回答[5]を参考にxmlで設定したかったんですが、うまくいかず……。
App.xml.cs
public partial class App : Application { static MainWindow objMainWindow; static SubWindow objSubWindow; static AppViewModel objAppViewModel; protected override void OnStartup(StartupEventArgs e) { objAppViewModel = new AppViewModel(); objMainWindow = new MainWindow( objAppViewModel ); objSubWindow = new SubWindow( objAppViewModel ); objMainWindow.Show(); objSubWindow.Show(); } }
実際には別のサイトも見たような気もしますが、見失ってしまいした残念……。多分stackOverFlowだったと思うんだけどな……。こまめにメモを取るなり、ブクマするなり、すぐに書くなりしないとだめですね。
以下のコードも書き足す必要があります。
MainWindow.xaml.cs
public MainWindow(AppViewModel sharedViewModel) { this.DataContext = sharedViewModel; InitializeComponent(); }
一部抜粋です。SubWindowも同じことをしてあげます。
window作成時に、applicationレベルからviewModelをinjectしてあげることにしました。 dataContextを設定できればいいので別にこれでよかったんですね。
複数のwindow、viewから単一のviewModelを参照することができました。
これでアプリを動かすと以下の様になります。同時に文字列が更新されているので成功していることがわかります。
2025/02/01追記
Prismというライブラリを利用しないといけない記述をどこかで見た気がしていたので書いていましたが、削除しました。どこでみたんだろうか、本当に……。