Browsable(false) with DesignerSerializationVisibility(Content) - winforms

Is it possible to keep a property completely hidden from the property grid but still serialized by the designer?
I have a Parent property on a tray component that sets itself to the form's instance using the designer service from ISite. It gets serialized fine, but it bugs me that it shows up in the property grid even with Browsable(false) applied to it.
Are there custom designer or even custom code generation options?

It is unclear why you need to solve that problem, but we have nothing to look at. This sample component certainly doesn't show the host in the Properties window:
using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Windows.Forms;
public partial class Component1 : Component {
private ContainerControl parent;
[Browsable(false)]
public ContainerControl ContainerControl {
get { return parent; }
set { parent = value; }
}
public override ISite Site {
set {
// Runs at design time, ensures designer initializes ContainerControl
base.Site = value;
if (value == null) return;
IDesignerHost service = value.GetService(typeof(IDesignerHost)) as IDesignerHost;
if (service == null) return;
IComponent rootComponent = service.RootComponent;
this.ContainerControl = rootComponent as ContainerControl;
}
}
}

Related

How to display new modal form in ReactiveUI 6.5

I am one of a team of developers currently maintaining a large suite of applications written using the WinForms UI.
In order to improve testability of our applications, we are wanting to move to an MVVM style, to separate the UI from the business logic. However, we need to keep using the WinForms UI, to minimize impact on our users as they work with different applications in the suite.
In trialing ReactiveUI, I have got a handle on how to bind form controls and commands to my view model, but cannot find documentation or examples on how to pop up a modal form to ask for or display additional information. For example these documentation pages on routing mention every supported UI framework except WinForms: http://docs.reactiveui.net/en/user-guide/routing/index.html, https://github.com/reactiveui/ReactiveUI/blob/docs/docs/basics/routing.md
Unfortunately, the ReactiveUI "good examples page" does not appear to have any WinForms-based examples, and all the other ReactiveUI / WinForms examples I can find using Google are only a single form.
I definitely want to keep forms/views out of the view model to maintain testability.
I believe the right way is to have a ReactiveCommand that is triggered by some user action in the view (such as clicking a button, selecting a menu item), but:
What should the command do?
Should it use Routing even though WinForms is not mentioned in the documentation? If yes, how is Routing done in a WinForms application?
How would the command/routing request the new form gets shown modally?
For simple messages and yes/no answers, I would look at Wayne Maurer's example for using UserError. I've used his example in Winform projects.
For something more complex, I was having the same difficulties finding any Winforms examples for routing. My google searches finally landed me in the source code for ReactiveUI.Winforms, where I discovered that Paul already has a UserControl for Winforms that will host routed UserControl views. It's called RoutedControlHost.
Using that code, I hacked something together that will show modal forms. I'm sure this isn't the best way to do it, but it might give you ideas.
RoutedModalHost
using Microsoft.Win32.SafeHandles;
using ReactiveUI;
using System;
using System.ComponentModel;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace ReactiveUI_Test_Routing
{
public class RoutedModalHost : ReactiveObject, IDisposable
{
readonly CompositeDisposable disposables = new CompositeDisposable();
RoutingState _Router;
IObservable<string> viewContractObservable;
public RoutedModalHost()
{
this.ViewContractObservable = Observable.Return(default(string));
var vmAndContract =
this.WhenAnyObservable(x => x.Router.CurrentViewModel)
.CombineLatest(this.WhenAnyObservable(x => x.ViewContractObservable),
(vm, contract) => new { ViewModel = vm, Contract = contract });
Form viewLastAdded = null;
this.disposables.Add(vmAndContract.Subscribe(x => {
if (viewLastAdded != null)
{
viewLastAdded.Dispose();
}
if (x.ViewModel == null)
{
return;
}
IViewLocator viewLocator = this.ViewLocator ?? ReactiveUI.ViewLocator.Current;
IViewFor view = viewLocator.ResolveView(x.ViewModel, x.Contract);
view.ViewModel = x.ViewModel;
viewLastAdded = (Form)view;
viewLastAdded.ShowDialog();
}, RxApp.DefaultExceptionHandler.OnNext));
}
[Category("ReactiveUI")]
[Description("The router.")]
public RoutingState Router
{
get { return this._Router; }
set { this.RaiseAndSetIfChanged(ref this._Router, value); }
}
[Browsable(false)]
public IObservable<string> ViewContractObservable
{
get { return this.viewContractObservable; }
set { this.RaiseAndSetIfChanged(ref this.viewContractObservable, value); }
}
[Browsable(false)]
public IViewLocator ViewLocator { get; set; }
bool disposed = false;
SafeHandle handle = new SafeFileHandle(IntPtr.Zero, true);
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposed)
return;
if (disposing)
{
handle.Dispose();
// Free any other managed objects here.
//
this.disposables.Dispose();
}
// Free any unmanaged objects here.
//
disposed = true;
}
}
}
MainViewModel
using ReactiveUI;
using System.Reactive.Linq;
using System;
namespace ReactiveUI_Test_Routing
{
public class MainViewModel : ReactiveObject, IScreen
{
public RoutingState Router { get; private set; }
public ReactiveCommand<object> ShowTestModalForm { get; protected set; }
public MainViewModel(RoutingState modalRouter)
{
Router = modalRouter;
ShowTestModalForm = ReactiveCommand.Create();
ShowTestModalForm.Subscribe(x => Router.Navigate.Execute(new TestModalFormViewModel(this)));
}
}
}
MainView
using System.Windows.Forms;
using Splat;
using ReactiveUI;
namespace ReactiveUI_Test_Routing
{
public partial class MainView : Form, IViewFor<MainViewModel>
{
public MainView()
{
InitializeComponent();
IMutableDependencyResolver dependencyResolver = Locator.CurrentMutable;
dependencyResolver.Register(() => new TestModalFormView(), typeof(IViewFor<TestModalFormViewModel>));
RoutingState router = new RoutingState();
RoutedModalHost modalHost = new RoutedModalHost();
modalHost.Router = router;
this.BindCommand(ViewModel, vm => vm.ShowTestModalForm, v => v.ShowTestModalForm);
ViewModel = new MainViewModel(router);
}
public MainViewModel ViewModel { get; set; }
object IViewFor.ViewModel
{
get { return ViewModel; }
set { ViewModel = (MainViewModel)value; }
}
}
}
TestModalFormViewModel
using ReactiveUI;
namespace ReactiveUI_Test_Routing
{
public class TestModalFormViewModel : ReactiveObject, IRoutableViewModel
{
public IScreen HostScreen { get; protected set; }
public string UrlPathSegment { get { return "ModalForm"; } }
public TestModalFormViewModel(IScreen screen)
{
HostScreen = screen;
}
}
}

Threestate checkbox inital binding Windows Store App / RT

my checkbox doesn't bind the initial value correctly on startup:
<CheckBox IsThreeState="True" IsChecked="{Binding StartWithSettings,Mode=TwoWay}"/>
The checkbox is displayed empty on startup, but should be nulled (the box with the black square in it).
Getter is properly raised with null on startup, what am I missing?
EDIT:
Below you can find my viewmodel, model code and a button to switch all three states of the checkbox. the strange thing happens when switching between null state and false state -> it always shows the false checkbox, whether its null or false, but the underlying data is correct.
do i toggle the checkboxstate directly by clicking the checkbox itself, all three states are displayed correctly.
It is a windows 8.1 store app, maybe the wpf checkbox control is another than the "usual" wpf checkbox and has a bug?
viewmodel snippet:
public bool? StartWithSettings
{
get
{
return _configurationModel.MyAppModel.StartWithSettings;
}
set
{
_configurationModel.MyAppModel.StartWithSettings = value;
RaisePropertyChangedEvent("StartWithSettings");
}
}
model snippet
public class MyAppModel
{
public bool? StartWithSettings { get; set; }
public MyAppModel()
{
this.StartWithSettings = null;
}
}
snippet test code
private void ChangeCheckboxState()
{
if (StartWithSettings == null)
{
StartWithSettings = true;
return;
}
else if (StartWithSettings == true)
{
StartWithSettings = false;
return;
}
else
StartWithSettings = null;
}
The backing property that is bound to the property must be of type bool? in order to support 3 state check box. Make sure that the backing field is set to null.
Also, you don't need to set IsThreeState="True"
EDIT: Since you mentioned Windows 8.1 and I assume this would be WinRT.
Nullable types are not supported in WinRT/Win8 Dev.
A solution would be here

Binding ComboBox and ObservableCollection<KeyValue> in wpf

in My OpenViewModel i collect data:
private ObservableCollection<KeyValue> availableData;
public ObservableCollection<KeyValue> AvailableDatas
{
get { return availableData; }
set
{
if (value != availableData)
{
availableData= value;
NotifyOfPropertyChange("AvailableDatas");
}
}
}
method for collecting data:
public ObservableCollection<KeyValue> CollectData()
{
ConnectorClient client = null;
try
{
client = webservice.GetClient();
AvailableDatas = client.GetDatas();
client.Close();
}
catch (Exception ex)
{
webservice.HandleException(ex, client);
}
return AvailableDatas;
}
How to call the method CollectData in wpf and fill my COmboBox?
thx
You might simply call the method the first time the AvailableDatas property is accessed (e.g. from a binding in XAML):
private ObservableCollection<KeyValue> availableData;
public ObservableCollection<KeyValue> AvailableDatas
{
get
{
if (availableData == null)
{
availableData = CollectData();
}
return availableData;
}
set
{
if (value != availableData)
{
availableData = value;
NotifyOfPropertyChange("AvailableDatas");
}
}
}
Then you should change the CollectData method in a way that is does not also set the property:
public ObservableCollection<KeyValue> CollectData()
{
ConnectorClient client = null;
ObservableCollection<KeyValue> data = null;
try
{
client = webservice.GetClient();
data = client.GetDatas();
client.Close();
}
catch (Exception ex)
{
webservice.HandleException(ex, client);
}
return data;
}
You could override the OnActivated() event assuming you are using an IScreen implementation and load data in there, or just do it in the constructor or a custom Initialise method if you want to roll your own (or in the property accessor as someone has already said).
You can also use coroutines if you want some visual context for the user and a better tie in with CM actions
There is a nice simple implementation of a Loader class here which helps provide visual context to the user:
https://caliburnmicro.codeplex.com/wikipage?title=IResult%20and%20Coroutines&referringTitle=Documentation
This searches the visual tree for a BusyIndicator control and activates it whilst the content is loading e.g. ...
public class SomeViewModel : Screen
{
protected override void OnActivate()
{
RefreshData();
}
public void RefreshData()
{
Coroutine.BeginExecute(LoadData(), new ActionExecutionContext() { Target = this });
}
public IEnumerable<IResult> LoadData()
{
yield return Loader.Show("Loading Data...");
yield return new LoadSomeDataRoutine(client.GetDatas);
yield return Loader.Hide();
}
}
The reason to have a RefreshData method is that this also allows you to bind CM actions and allows the coroutine can grab more contextual information.
Obviously you have less need to worry about the async->sync benefits this gives in Silverlight because you are using WPF (but it still applies to async web service calls), however it still has many benefits and it also helps you to write reusable routines which become part of your application framework (e.g. some level of error handling/logging encapsulated in the IResult implementation etc)
You also mentioned filling the combobox... all you would need to do in CM is place a combobox on your control, and set it's Name property to the name of the property on your VM:
public class SomeViewModel : Screen
{
public ObservableCollection<MyObject> MyProperty { //blah blah... }
}
<UserControl .... blah>
<ComboBox x:Name="MyProperty" />
</UserControl>
This will fill the combobox with the items. You will still need to set the binding for SelectedItem/SelectedValue
I assume you know this already though - if not CM has some decent documentation:
https://caliburnmicro.codeplex.com/wikipage?title=Basic%20Configuration%2c%20Actions%20and%20Conventions&referringTitle=Documentation

silverlight: How to implement dynamic object creation in POCO class properties?

We're porting our data model from WPF over to Silverlight. On the WPF side, every element of the data model supports dynamic initialization so that we don't have to worry about any bookkeeping. For example:
public UnitNameClass UnitName
{
get
{
if ((this.unitNameField == null))
{
this.unitNameField = new UnitNameClass();
}
return this.unitNameField;
}
set
{
if (((this.unitNameField == null)
|| (this.unitNameField.Equals(value) != true)))
{
this.unitNameField = value;
this.OnPropertyChanged("UnitName"));
}
}
}
The majority of the classes are generated for us, from an XSD representing the data model. There are some other extension classes we've added which are not in the XSD files.
Silverlight generates properties of the following form for its proxy classes:
public UnitNameClass UnitName
{
this.OnCreated();
}
public UnitNameClass UnitName
{
get
{
return this._unitName;
}
set
{
if ((this._unitName != value))
{
this.OnUnitNameChanging(value);
this.RaiseDataMemberChanging("UnitName");
this.ValidateProperty("UnitName", value);
this._unitName = value;
this.RaiseDataMemberChanged("UnitName");
this.OnUnitNameChanged();
}
}
}
Obviously, we're meant to put initialization of all the properties in the OnCreated partial function, but we'd much rather have the ability to add some logic to the get property.
Has anyone ever had this problem before?

Is there any way of checking if a DataGrid in Silverlight has Focus?

I have a Silverlight DataGrid of which I need to check if it has Focus. I know there is a method to set Focus and an event for GotFocus but can't see anyhting for checking if it has focus.
Any Ideas ?
AFAIK there is no direct method or property to check if it has focus, but you should be able to use the FocusManager.GetFocusedElement().
If you then define a extension method, you should be able to call MyDataGrid.HasFocus():
public static class ControlExtensions
{
public static bool HasFocus(this Control aControl)
{
return System.Windows.Input.FocusManager.GetFocusedElement() == aControl;
}
}
[edited: I did test it now:]
However there is catch: the call GetFocusedElement() can return the current focused cell within the DataGrid. So in that case the HasFocus will return false.
To be able to check if the DataGrid or one of its cells are focused, we can adapt our extension method like this
public static class ControlExtensions
{
public static bool HasFocus(this Control aControl, bool aCheckChildren)
{
var oFocused = System.Windows.Input.FocusManager.GetFocusedElement() as DependencyObject;
if (!aCheckChildren)
return oFocused == aControl;
while (oFocused != null)
{
if (oFocused == aControl)
return true;
oFocused = System.Windows.Media.VisualTreeHelper.GetParent(oFocused);
}
return false;
}
}
Hope this helps a bit?

Resources