Does ViewModelViewHost work at design time for WPF? (ReactiveUI) - wpf

I cannot get a ViewModelViewHost to work at design time in Visual Studio. Is this by design or have I set something up wrong?
In my view's ctor I have:
Locator.CurrentMutable.InitializeSplat();
Locator.CurrentMutable.InitializeReactiveUI();
Locator.CurrentMutable.Register(() => new SessionView(), typeof(IViewFor<SessionViewModel>));
In my view's XAML I have:
<d:DesignProperties.DataContext>
<local:MainWindowViewModel>
<local:MainWindowViewModel.ChildViewModel>
<local:SessionViewModel/>
</local:MainWindowViewModel.ChildViewModel>
</local:MainWindowViewModel>
</d:DesignProperties.DataContext>
<reactiveUi:ViewModelViewHost ViewModel="{Binding ChildViewModel}"/>
SessionView is an IViewFor<SessionViewModel>.
There is a comment here in the ViewModelViewHost ctor indicating that in design mode it will return before trying to create a view. But it seems strange that InUnitTestRunner should return true if there is a seperate InDesignMode property for that purpose.
// NB: InUnitTestRunner also returns true in Design Mode
if (ModeDetector.InUnitTestRunner()) {
ViewContractObservable = Observable.Never<string>();
return;
}

Bit of a late reply our apologies.
The answer is this is deliberate.
We have stuff that will break the XAML designer if ReactiveUI's code is allowed to initialize in the constructor. Hence why we don't run the values.

Related

Cannot Browse to specific Type in Settings designer for WPF/.net Core application

When I've used Settings Designer before, I've been able to browse to find non-standard Types (e.g. uncommon enums etc) to use in my Settings via a "Browse" button at the bottom of the drop down under the "Type" column. I'm developing a WPF desktop application for .net Core and there is no Browse option as pictured below:
I did go into the code behind (Settings.Designer.cs.) and edit the code manually, but on saving, this just reverted to string. I'm guessing this may have something to do with settings also having an element in App.config and I notice it has a "serialiseAs" tag - didn't know what to put here. Exmaple of the code behind settings and App.config:
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string UiTheme {
get {
return ((string)(this["UiTheme"]));
}
set {
this["UiTheme"] = value;
}
}
<userSettings>
<GameBoxer.WPF.Properties.Settings>
<setting name="UiTheme" serializeAs="String">
<value />
</setting>
</GameBoxer.WPF.Properties.Settings>
</userSettings>
Does anyone know how to bring back the 'Browse'?? Or, how to correctly do it in code?
I'm using Visual Studio 2022 Community
Thanks
UPDATE: So, I learn that this is "By Design" in VS2022 according to MS here. It's still present in VS2019! But they've taken it out of VS2022 and I can't figure how to do it in code. MS, you're one of my faves out the bunch, but sometimes, you're as mad as a box of frogs. unfortunately that link doesn't provide the poster with any alternatives other than "that's not a bug." Not very helpful, really.
As mentioned in the link you provided, this change was by design due to .NET Core and while I very strongly disagree with their stance on this - I'm assuming this was done because it could be quite fiddly to get your own types to work as expected, especially for new users.
One simple workaround if your custom data has several values, you can use string and simply write your own little parser using delimiters such as ;. You could also use StringCollection to achieve the same result.
Inconvenient, yes. But a simple solution nonetheless.
I sincerely hope Microsoft changes their stance on this and looks at reimplementing this as it worked remarkably well once you figured out the procedure to get it to serialize properly.
Edit:
Figured I might as well provide an example;
// Storing the Settings
// Parameter: Struct { Location(Point), Size(Point), Margin(Thickness) }
var settingString = $"{e.Location.X};{e.Location.Y};{e.Size.X};{e.Size.Y};{e.Margin.Left};{e.Margin.Top};{e.Margin.Right};{e.Margin.Bottom}";
Properties.Settings.Default.MySetting = settingString;
Properties.Settings.Default.Save();
// Parsing the Saved Setting
var settingString = Properties.Settings.Default.MySetting;
if (!String.IsNullOrWhiteSpace(settingString))
{
List<string> splitStrings = settingString.Split(';', StringSplitOptions.RemoveEmptyEntries).ToList();
List<double> parsedValues = new List<double>();
splitStrings.ForEach(x => parsedValues.Add(double.Parse(x)));
var location = new Point(parsedValues[0], parsedValues[1]);
var size = new Point(parsedValues[2], parsedValues[3]);
var margin = new Thickness(parsedValues[4], parsedValues[5], parsedValues[6], parsedValues[7]);
}
There's probably better ways of doing this, but I find this to be a very simple workaround and has worked great thus far.

Xceed DataGrid: Filtering Details

I've got a Master/Detail DataGrid and I want to filter the details.
Here's my DataGridCollectionViewSource:
<xcdg:DataGridCollectionViewSource x:Key="Features"
Filter="ExampleFilter"
Source="{Binding Path=ItemUnderEdit.Features}"
AutoCreateDetailDescriptions="False"
AutoCreateItemProperties="False">
<xcdg:DataGridCollectionViewSource.DetailDescriptions>
<xcdg:PropertyDetailDescription RelationName="Settings"
AutoCreateDetailDescriptions="False"
AutoCreateItemProperties="False">
</xcdg:PropertyDetailDescription>
</xcdg:DataGridCollectionViewSource.DetailDescriptions>
</xcdg:DataGridCollectionViewSource>
As you can see I'm filtering it with ExampleFilter, but this only filters the master. I put a breakpoint and it never sees any details.
I cant add a filter to the Detail Descriptions in the same way. Is there any way to filter the details? Any help would be much appreciated!
I went up against this problem today - I had a simple filter for both the master and detail sections that gets turned on / off via code. For the master section, it was a simple matter of code like:
((DataGridCollectionView)grid.ItemsSource).FilterCriteriaMode = FilterCriteriaMode.None; // Off
((DataGridCollectionView)grid.ItemsSource).FilterCriteriaMode = FilterCriteriaMode.And; // On
((DataGridCollectionView)grid.ItemsSource).Refresh(); // Re-run filter.
For the details section, it should have been as simple as the following code (it wasn't though):
MyDetailDescription.FilterCriteriaMode = FilterCriteriaMode.None; // Off
MyDetailDescription.FilterCriteriaMode = FilterCriteriaMode.And; // On
Turns out, doing that will enable the new filter for any new detail sections that get generated, but not existing ones. New detail sections are generated when the master row is expanded. To get around this it turned out I needed a simple foreach loop such as:
foreach (DataGridContext context in grid.GetChildContexts()) {
((DataGridCollectionViewBase)(context.Items)).FilterCriteriaMode = PetsDetailDescriptions.FilterCriteriaMode;
}
Here's my complete(ish) code for all that:
public bool ShowDeleted {
set {
if ((grid.ItemsSource != null) && (grid.ItemsSource.GetType() == DataGridCollectionView));
DataGridCollectionView v = ((DataGridCollectionView)(grid.ItemsSource));
if (value) {
v.FilterCriteriaMode = FilterCriteriaMode.None;
MyDetailDescription.FilterCriteriaMode = FilterCriteriaMode.None;
}
else {
v.FilterCriteriaMode = FilterCriteriaMode.And;
MyDetailDescription.FilterCriteriaMode = FilterCriteriaMode.And;
}
foreach (DataGridContext context in grid.GetChildContexts()) {
((DataGridCollectionViewBase)(context.Items)).FilterCriteriaMode = PetsDetailDescriptions.FilterCriteriaMode;
}
v.Refresh();
}
}
}
I'm using that in-conjunction with a simple predefined filter criterion in the XAML. IE:
<g:DataGridItemProperty Name="IsDeleted"
DataType="{x:Type sys:Boolean}">
<g:DataGridItemProperty.FilterCriterion>
<g:EqualToFilterCriterion>
<sys:Boolean>False</sys:Boolean>
</g:EqualToFilterCriterion>
</g:DataGridItemProperty.FilterCriterion>
</g:DataGridItemProperty>
I recommend using the Xaml FilterCriterions, because if you absolutely need the Filter event, it's going to get a bit more messy. For that route, you need to do the following steps:
Tap into the event when a new child DataGridContext is added to the control.
Add a predicate reference to the context.Items.Filter property (in the code state, this is a property expecting predicate, not an event).
Write your filter code in the predicate function.
I'm not 100% sure how to achieve #1 above (as I didn't need to go that route). However, a good place to possible start is the DetailsExpanding and DetailsExpanded events of the DataGridControl. For the expanding, I'm not sure if the child DataGridContext exists yet (as there is an option to cancel the expanding). So you might have to wait until after the expanded event.
I hope this helps point you in the right direction.

Does anyone have a C# example of using an UltraDataSource as the DataSource to a UltraComboEditor please

Does anyone have a C# example of using an UltraDataSource as the DataSource to a UltraComboEditor please.
I can get so far but it doesn't seem to bind.
I have tried a simple project to use an UltraDataSource as datasource for a simple UltraComboEditor. Set the properties of the ComboEditor to
this.ultraComboEditor1.DataMember = "Band 0";
this.ultraComboEditor1.DataSource = this.udsTest; // <- crashed here
this.ultraComboEditor1.DisplayMember = "Description";
this.ultraComboEditor1.Name = "ultraComboEditor1";
this.ultraComboEditor1.ValueMember = "ID";
The sample program crashed with a NullReferenceException inside the InitializeComponent code where I set the UltraDataSource instance.
Then I have removed the setting of the property DataMember (Not just blanked out, but right-click and selected Reset). Now the program works.

ADF Invoke operation manually from code

I want to execute a data control operation (CreateInsert and Delete) from a buttons ActionListener. I am aware a data control button can be inserted from the Data Controls menu, but for various reasons I need to do it this way, a prominent one being I need to perform extra runtime checks.
I found the following code:
OperationBinding operation = bindings.getOperationBinding("operation_name");
operation.getParamsMap().put("parameter_name", parameterValue);
operation.execute();
But don't know which variables to use for myself. First of all, I don't know which binding I should use. Then, the operation name should, as far as I know, be CreateInsert, and for the next button, CreateInsert1. Thats whats used for UIBinding now (which I will remove).
The Data control I want to use the operation of is 'ARNG1'.
So in short, I need to know how to manually invoke this Data control's CreateInsert operation.
Thanks in advance.
See if this will help you:
https://blogs.oracle.com/shay/entry/doing_two_declarative_operatio
the code you want to execute an operation behind a actionlistener:
public BindingContainer getBindings() {
if (this.bindings == null) {
FacesContext fc = FacesContext.getCurrentInstance();
this.bindings = (BindingContainer)fc.getApplication().
evaluateExpressionGet(fc, "#{bindings}", BindingContainer.class);
}
return this.bindings;
}
BindingContainer bindings = getBindings();
OperationBinding operationBinding =
bindings.getOperationBinding("doQueryResultReset");
operationBinding.execute();
Similar to Joe's answer but does not use EL Expression evaluator and uses direct access instead to get the BindingContainer
//Get binding container
BindingContainer bindings = BindingContext.getCurrent().getCurrentBindingsEntry();
// get an Action or MethodAction
OperationBinding method = bindings.getOperationBinding("methodAction");
method.execute();
List errors = method.getErrors();

Silverlight/xaml - displaying child data in a datagrid

I have two tables in a database and using entity framework and ria services to display data in a simple datagrid. Here is the database/EF structure
Cars Make
----- ----
CarId MakeId
Car Make
MakeId
In my Silverlight datagrid I want to show the following two columns, for example
Car Make
--- -----
Escort Ford
Megane Renault
Rav4 Toyota
I can easily bind to the Cars table and show cars but I can't work out how to display the Make taken from the child table
The xaml that I am using to configure the datagrid is as follows:
<datagrid:DataGrid x:Name="CarGrid" AutoGenerateColumns="False" MinHeight="100" IsReadOnly="True" ItemsSource="{Binding ElementName=MyData, Path=Data}">
<datagrid:DataGrid.Columns>
<datagrid:DataGridTextColumn Header="Car" Binding="{Binding Car}"/>
<datagrid:DataGridTextColumn Header="Make" Binding="{Binding Cars.Make}"/>
......
The datagrid datasource binds to a DomainDataSource method "GetCars". I'm not sure if it is automatically loading the child table (not sure whether I have to explicitly tell it to or not, and have no idea how to do this in xaml).
I'm sure I could ditch the xaml and do it in c# but I'm trying to be a good coder and do it in xaml.
I find a good solution. Let's try this: http://jeffhandley.com/archive/2010/03/12/lookupdata.aspx
Then don't forget to "include" your child table in the Query lookup on your domain service class.
ex:
public IQueryable<Car> GetCars()
{
return this.ObjectContext.Cars.Include("Make");
}
replace the names with your own.
PS: remember to do all the steps that the blog indicates.
Unless you specify it explicitly somewhere (using Linq-to-SQL's DataContext.LoadOptions for example), the child record wouldn't be loaded automatically with the parent record.
Here's how it's done in Linq-to-SQL:
List<tblInventory> result;
using (var dc = new SMDataContext())
{
dc.Log = Console.Out;
var dlo = new DataLoadOptions();
dlo.LoadWith<tblInventory>(x => x.tblItemInfo);
dc.LoadOptions = dlo;
var q = (from o in dc.tblInventories
select o).Take(10);
result = q.ToList();
}
And here's the resulting log:
SELECT TOP 10 [t0].[fldItemPrivateSN], [t0].[fldCatNo], [t0].[fldSerNo], ...
..., [t1].[fldWeight], [t1].[fldValue], ...
FROM [dbo].[tblInventory] AS [t0]
INNER JOIN [dbo].[tblItemInfo] AS [t1] ON [t1].[fldCatNo] = [t0].[fldCatNo]
-- Context: SqlProvider(Sql2000) Model: AttributedMetaModel Build: 3.5.30729.1
Update: Also, it appears that you are binding to Cars.Make, try binding to Car.Make instead.
You need to change your binding for the Make column to Car.Make, and you need to ensure this Property is being populated by EF.
I'd suggest attaching a debugger to the service and inspecting what is coming out of EF.
You can also attach SQL Profiler to your SQL Server instance and see what query EF is running.
Mike Hilberg's article addresses much of what you are interested in:
http://blogs.msdn.com/mikehillberg/archive/2009/03/26/implementing-selectedvalue-with-the-silverlight-combobox.aspx
as does Manish Dalal's article:
http://weblogs.asp.net/manishdalal/archive/2008/09/28/combobox-in-datagrid.aspx
Even with the help of these examples I struggled to implement the same sort of thing as you (using hand-crafted MVVM rather than RIA).
I ended up with an inelegant hack which did compromise the underlying objects (something you would like to avoid) and that was difficult enough.
Good luck.

Resources