A bit of a complex one. I'm using WPF MVVM and I need to display results in a grid, then when you double click on one it loads that result in a separate popup window.

To do this, I have created a ResultViewerService which takes as parameters the ViewModel to use as content for this popup and a callback to call when the window is closed.

What I want to be able to do, is set a dependency property on the ViewModel and have this re-size the popup windows width based on the property's value. So if the user clicks a button, I can use the ViewModel to double the popup window's width and "expand" the window sideways to show all results. If the user then clicks contract, it returns to the original width.

I can re-size all the content within the window but because of the way I am creating the popup programmatically, I can't figure out how to link the Width of the popup window to the property on the ViewModel contained within the content.

My popup creation service method is as follows

 public static Window OpenNew(ResultsViewModel viewModel, ResultsMainViewModel.CallbackResult callback)
        {
            var resultViewer = new ResultViewer(callback) { DataContext = viewModel };

            var panel = new StackPanel { Margin = new Thickness(0), Name = "ParentPanel" };
            panel.Children.Add(resultViewer);

            var win = new Window
                          {
                              Owner = Application.Current.MainWindow,
                              WindowStyle = WindowStyle.ToolWindow,
                              WindowStartupLocation = WindowStartupLocation.CenterOwner,
                              Opacity = 1,
                              ShowInTaskbar = false,
                              ResizeMode = ResizeMode.NoResize,
                              Height = 690,
                              Width = ResultsConstants.ResultsWidthExpanded,
                              Margin = new Thickness(0),
                              Padding = new Thickness(0),
                              Content = panel,
                              Topmost = false,
                              Background =
                                  new ImageBrush
                                      {
                                          ImageSource =
                                              new BitmapImage(new Uri(@"pack://application:,,,/WealthMarginAnalyser;component/Resources/Background2.jpg", UriKind.Absolute))
                                      }
                          };

            win.Closed += resultViewer.ResultViewer_Closed;
            win.Show();

            return win;
        }

The ResultViewer class is the XAML user control that I use for the popup content. So all I am doing in the popup service above is creating a Window programmatically, setting the content as a StackPanel with only one child, the ResultViewer user control which has the DataContext set to the ViewModel. I then set a number of properties on the window programmatically such as width, margin, show in taskbar etc and then show the popup window.

You can see in the above example I am currently hard coding the Width property of the window to the Expanded size, just for testing. But I want this Width property instead to take it's value from the ViewModel's dependency property I have created called ScreenWidth. When I update that property, I want the window to resize accordingly.

How can I achieve this?

I have tried in the past to create Bindings manually eg

Width = new Binding(...) 

But I'm not sure if I can achieve this result this way or how I would do it.

The other way is from the ViewModel, to somehow get a reference to the popup window as an object (not pure MVVM of course) and set the Width manually.

Can anyone help me with suggestions?

UPDATE:

I have added the following line to the Window object creation in my service above

DataContext = viewModel

So the window itself has it's datacontext set to the VM, not just the ResultViewer user control. I then have added the following line after the window object creation.

win.SetBinding(FrameworkElement.WidthProperty, new Binding("ScreenWidth"));

This almost works. The window initially loads at the correct size when I open the popup and if I click expand, all the content resizes, but the window itself doesn't. If you close the popup however and re-open it immediately, it comes up at the expanded size. So it seems to be picking up the dependency property fine but ONLY on window creation. If you update the dependency property while the popup is open, it doesn't get the notification that something has changed and to change the width dynamically. I am calling RaisePropertyNotification as required and the user control updates in real-time, so property notification is working, it just doesn't work from the parent window width's perspective.

Is there something else I need to do to wire the INotifyPropertyChanged up to the windows binding I have created programmatically?

有帮助吗?

解决方案

At first, you can create new Window using VisualStudio (e.g. Add->New Item->Window(WPF)). After this you can set all properties of window in XAML:

Width="{Binding Path=MyWidth, Mode=TwoWay}" ShowInTaskbar = "False", ...

Then you can instantiate your window and give it data context:

....
var window = new MyWindow();
window.DataContext = MyViewModel;
win.Closed += resultViewer.ResultViewer_Closed;
win.Show();
return win;
...

Hope this help.

其他提示

I suggest you do all this in XAML. Create a ResultsWindow, assign its DataContext to the view model and add whichever bindings you need. For example:

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        x:Class="MyApp.ResultsWindow"
        Height="{Binding WindowHeight}" 
        WindowStyle="ToolWindow"
        Background="...">
    <ResultViewer />
</Window>

Then in code:

var win = new ResultsWindow { DataContext = viewModel };
win.Show();
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top