How to disable custom window rendering in WPF designer? - wpf

I have created window derived class (WindowAttachedCollection.MyWindow) and attached property which holds collection of these windows. But WPF designer in VS 2010 tries to create WindowInstance object for each window in that collection and it throws ArgumentException:
The value "Microsoft.Expression.Platform.WPF.InstanceBuilders.WindowInstance" is not of type "WindowAttachedCollection.MyWindow" and cannot be used in this generic collection.
Parameter name: value
So it breaks WPF designer.
Is there any way how to disable instancing WindowInstance instead of MyWindow in WPF designer? At this time I don't require any design-time support for this collection of MyWindow.
EDIT:
public static readonly DependencyPropertyKey DialogsPropertyKey = DependencyProperty.RegisterAttachedReadOnly(
"DialogsInternal",
typeof(ObservableCollection<MyWindow>),
typeof(MyWindow),
new PropertyMetadata(null));
public static readonly DependencyProperty DialogsProperty = DialogsPropertyKey.DependencyProperty;
public static void SetDialogs(UIElement element, ObservableCollection<MyWindow> value)
{
element.SetValue(DialogsPropertyKey, value);
}
public static ObservableCollection<MyWindow> GetDialogs(UIElement element)
{
var dialogs = (ObservableCollection<MyWindow>)element.GetValue(DialogsProperty);
if (dialogs == null)
{
dialogs = new ObservableCollection<MyWindow>();
SetDialogs(element, dialogs);
}
return dialogs;
}

Since your code will actually be executed at design time, you can simply have it conditionally do something that will make the designer not do anything unpleasant, to the extent that that is possible. To accomplish this you need to be able to detect programmatically that you are running under the designer and you can use DesignerProperties.IsInDesignModeProperty for that as described here:
Detecting design time mode in WPF and Silverlight

I decided to change base class of MyWindow from Window to ContentControl. For our purposes it is sufficient. Each ContentControl is wrapped into a Window when becomes active.

Related

How to write a WPF user control in F#?

Can a WPF user control be written in F#?
Lets say I have a standard WPF/C# user control as:
public class DataGridAnnotationControl : UserControl
{
static DataGridAnnotationControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(DataGridAnnotationControl), new FrameworkPropertyMetadata(typeof(DataGridAnnotationControl)));
}
public DataGridAnnotationControl()
{
BorderBrush = Brushes.Black;
Background = Brushes.AliceBlue;
BorderThickness = new Thickness(20, 20, 20, 20);
}
public string LastName
{
get { return (string)GetValue(LastNameProperty); }
set { SetValue(LastNameProperty, value); }
}
public static readonly DependencyProperty LastNameProperty =
DependencyProperty.Register("LastName", typeof(string), typeof(DataGridAnnotationControl), new PropertyMetadata(string.Empty));
}
How is this coded in F#?
TIA
In general, creating the user control in F# (without a library) will typically be quite different than in C#.
The main issue is you can't use partial classes, so the designer will not function. Even if you ditch the designer, the typical workflow with XAML files does not work properly. To do this in "pure" F#, you typically need to write the UI in code vs doing it in XAML and allowing the generated InitializeComponent() method to wire things together.
However, one way to get there in a more "natural" method is to use FsXaml. It allows you to write user controls directly which become usable in a similar way to C# developed ones. This is done via a type provider and overriding the default information.

Caliburn.Micro - why uses UserControl instead of Window

My question is exactly like in the title.
I'm starting with Caliburn.Micro for MVVM approach (which also is new for me) and in every tutorial the first step is to remove the default MainWindow.xaml file and create a new UserControl file. Why is that? UserControl does not even accept a Title. Isn't it possible to build application using normal Windows? I already tried that, but with every launch I get error "Cannot find view for ViewModel", although both MainView.xaml and MainViewModel.cs are present. When I created a pair of USerControl and ViewModel for it, everything started to work as expected. So again, why Windows don't work?
It wouldn't really be a problem, but I'm thinking that some additions like Modern UI themes for WPF might not work without a window. I'm not sure of that.
Probably one solution would be to display a defined UserControl View inside of a Window, but it's just a workaround.
You could create your own custom shell window by creating a custom WindowManager:
public class CustomWindowManager : WindowManager
{
protected override Window CreateWindow(object rootModel, bool isDialog, object context, IDictionary<string, object> settings)
{
Window window = new Window();
window.Title = "custom...";
return window;
}
}
...that you register in your bootstrapper:
public class HelloBootstrapper : BootstrapperBase
{
...
protected override void Configure()
{
_container.Singleton<IWindowManager, CustomWindowManager>();
...
}
}

How do I databind to a Winform control that is hosted in a WPF control?

I just thought about converting one of our custom controls to WPF, however it uses another custom control of ours that is written Winforms.
As there is little point in using WPF without MVVM. How can I databind to a Winforms control that is used within a WPF control.
(I don’t have much WPF experience, so I may be missing the point completely)
I think you will have to wrap the WinForms control in a class exposing DependencyProperties or at least implementing INotifyPropertyChanged.
So you'd have a class such as:
public class WinFormsWrapper : WindowsFormsHost
{
//You'll have to setup the control as needed
private static MyWinFormsControl _control;
public static readonly DependencyProperty IsSpinningProperty = DependencyProperty.Register("IsSpinning", typeof(bool), typeof(WinFormsWrapper),
new FrameworkPropertyMetadata(_control.IsSpinning, new PropertyChangedCallback(IsSpinning_Changed)));
private static void IsSpinning_Changed(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
_control.IsSpinning = (bool)e.NewValue;
}
public bool IsSpinning
{
get { return (bool)GetValue(IsSpinningProperty); }
set { SetValue(IsSpinningProperty, value); }
}
}
Assuming that you have an IsSpinning property on your WinForms control. Depending on your needs, it may be simpler to implement INotifyPropertyChanged instead of using DependencyProperties.
Added by Ian Ringrose:
This example code is clearly wrong (see comments about _control being static), but shows how to solve the problem. As I am not using WPF at present, I am not going to edit the code as I can't test my edits.
I am keeping this answer as the accepted answer, as it contains the information needed to solve the problem.
I have added this to the answer, as comments do sometimes get deleted and this is getter views from people doing google searches.

Using WPF, MVVM and Bindings with a WinForm UserControl, how to integrate successfully?

I have a WinForm UserControl inside a WPF window and the WPF code is using the MVVM pattern.
What is the best way to successfully integrate the WinForm control into the MVVM pattern?
Can I use some form of binding from the WPF side?
Let's say that I want to handle some events from the WF control, is there a way to fully go MVVM?
Thanks.
Note that this doesn't really answer the questions (I should have read better). If you're interested in using a WPF control in a WinForms app, here's an approach. My scenario is:
1) Have a WinForms control that is used many places in my app.
2) Want to develop a WPF implementation that will use the MVVM pattern.
3) Want to write the control as a proper WPF control complete with dependency properties so it can be used properly when my app is eventually all WPF.
4) Want to keep the same WinForms control and API to not break existing client code in my app.
Most everything was straightforward except for having my WinForms control raise events when properties of my WPF control changed. I wanted to use a binding but since the source of a binding must be a DependencyObject and a System.Windows.Forms.UserControl is not, I had to make a simple nested class. I wrote my WPF control exactly as if I was integrating it into a WPF application, and just did some extra thunking to get my WinForms wrapper to work.
Here's code for my WPF control:
public partial class MonkeySelector : UserControl
{
public static readonly DependencyProperty SelectedMonkeyProperty =
DependencyProperty.Register(
"SelectedMonkey", typeof(IMonkey),
typeof(MonkeySelector));
public MonkeySelector()
{
InitializeComponent();
}
protected override void OnInitialized(EventArgs e)
{
base.OnInitialized(e);
// Note: No code is shown for binding the SelectedMonkey dependency property
// with the ViewModel's SelectedMonkey property. This is done by creating
// a Binding object with a source of ViewModel (Path = SelectedMonkey) and
// target of the SelectedMonkey dependency property. In my case, my
// ViewModel was a resource declared in XAML and accessed using the
// FindResource method.
}
public IMonkey SelectedMonkey
{
get { return (IMonkey)GetValue(SelectedMonkeyProperty); }
set { SetValue(SelectedMonkeyProperty, value); }
}
}
Here's the code for my WinForms control:
public partial class WinFormsMonkeySelector : UserControl
{
public event EventHandler SelectedMonkeyChanged;
private MonkeySelector _monkeySelector;
private WpfThunker _thunker;
public WinFormsMonkeySelector()
{
InitializeComponent();
_monkeySelector = new MonkeySelector();
_elementHost.Child = _monkeySelector;
System.Windows.Data.Binding binding = new System.Windows.Data.Binding("SelectedMonkey");
binding.Source = _monkeySelector;
binding.Mode = System.Windows.Data.BindingMode.OneWay;
_thunker = new WpfThunker(this);
// Note: The second parameter here is arbitray since we do not actually
// use it in the thunker. It cannot be null though. We could declare
// a DP in the thunker and bind to that, but that isn't buying us anything.
System.Windows.Data.BindingOperations.SetBinding(
_thunker,
MonkeySelector.SelectedMonkeyProperty,
binding);
}
protected virtual void OnSelectedMonkeyChanged()
{
if (SelectedMonkeyChanged != null)
SelectedMonkeyChanged(this, EventArgs.Empty);
}
public IMonkey SelectedMonkey
{
get { return _monkeySelector.SelectedMonkey; }
set { _monkeySelector.SelectedMonkey = value; }
}
private class WpfThunker : System.Windows.DependencyObject
{
private WinFormsMonkeySelector _parent;
public WpfThunker(WinFormsMonkeySelector parent)
{
_parent = parent;
}
protected override void OnPropertyChanged(System.Windows.DependencyPropertyChangedEventArgs e)
{
base.OnPropertyChanged(e);
// Only need to check the property here if we are binding to multiple
// properties.
if (e.Property == MonkeySelector.SelectedMonkeyProperty)
_parent.OnSelectedMonkeyChanged();
}
}
}
Personally, I would handle this by creating a WPF UserControl that wraps the Windows Forms control. This would allow you to encapsulate all of the required code-behind into your WPF Control, and then use it in a pure MVVM manner.
It will be difficult to stay "pure" MVVM using a Windows Forms control directly, as Windows Forms controls typically require a different binding model, as well as typically requiring direct event handling.
You might have a look at the WAF Windows Forms Adapter. It shows a possible way to use Windows Forms together with MVVM.

Drag and Drop in MVVM with ScatterView

I'm trying to implement drag and drop functionality in a Surface Application that is built using the MVVM pattern. I'm struggling to come up with a means to implement this while adhering to the MVVM pattern. Though I'm trying to do this within a Surface Application I think the solution is general enough to apply to WPF as well.
I'm trying to produce the following functionality:
User contacts a FrameworkElement within a ScatterViewItem to begin a drag operation (a specific part of the ScatterViewItem initiates the drag/drop functionality)
When the drag operation begins a copy of that ScatterViewItem is created and imposed upon the original ScatterViewItem, the copy is what the user will drag and ultimately drop
The user can drop the item onto another ScatterViewItem (placed in a separate ScatterView)
The overall interaction is quite similar to the ShoppingCart application provided in the Surface SDK, except that the source objects are contained within a ScatterView rather than a ListBox.
I'm unsure how to proceeded in order to enable the proper communication between my ViewModels in order to provide this functionality. The main issue I've encountered is replicating the ScatterViewItem when the user contacts the FrameworkElement.
You could use an attached property. Create an attached property and in the setproperty method bind to the droped event :
public static void SetDropCommand(ListView source, ICommand command)
{
source.Drop += (sender, args) =>
{
var data = args.Data.GetData("FileDrop");
command.Execute(data);
};
}
Then you can bind a command in your view model to the relevant control on the view. Obviously you may want to make your attached property apply to your specific control type rather than a listview.
Hope that helps.
I had a go at getting Steve Psaltis's idea working. It took a while - custom dependency properties are easy to get wrong. It looks to me like the SetXXX is the wrong place to put your side-effects - WPF doesn't have to go though there, it can go directly to DependencyObject.SetValue, but the PropertyChangedCallback will always be called.
So, here's complete and working the code for the custom attached property:
using System.Windows;
using System.Windows.Input;
namespace WpfApplication1
{
public static class PropertyHelper
{
public static readonly DependencyProperty DropCommandProperty = DependencyProperty.RegisterAttached(
"DropCommand",
typeof(ICommand),
typeof(PropertyHelper),
new PropertyMetadata(null, OnDropCommandChange));
public static void SetDropCommand(DependencyObject source, ICommand value)
{
source.SetValue(DropCommandProperty, value);
}
public static ICommand GetDropCommand(DependencyObject source)
{
return (ICommand)source.GetValue(DropCommandProperty);
}
private static void OnDropCommandChange(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ICommand command = e.NewValue as ICommand;
UIElement uiElement = d as UIElement;
if (command != null && uiElement != null)
{
uiElement.Drop += (sender, args) => command.Execute(args.Data);
}
// todo: if e.OldValue is not null, detatch the handler that references it
}
}
}
In the XAML markup where you want to use this, you can do e.g.
xmlns:local="clr-namespace:WpfApplication1"
...
<Button Content="Drop here" Padding="12" AllowDrop="True"
local:PropertyHelper.DropCommand="{Binding DropCommand}" />
.. And the rest is just making sure that your ViewModel, bindings and command is right.
This version passes an IDataObject through to the command which seems better to me - you can query it for files or whatever in the command. But that's just a current preference, not an essential feature of the answer.

Resources