Caliburn.Micro Action Message with StaticResource as parameter - caliburn.micro

How can i convert this long format to short inline format. I tried with various combinations but none worked. I always get the parameter as null.
<i:Interaction.Triggers>
<i:EventTrigger EventName="GotFocus">
<cal:ActionMessage MethodName="SelectTool">
<cal:Parameter Value="{StaticResource contrastTool}" />
</cal:ActionMessage>
</i:EventTrigger>
</i:Interaction.Triggers>
I tried with this:
cal:Message.Attach="[Event GotFocus] = [Action SelectTool({StaticResource contrastTool})]"
but this doesn't work

It can be solved using Caliburn.Micro Contrib (also available via Nuget).
To enable XamlBinding, insert below code in your bootstrapper
FrameworkExtensions.Message.Attach.AllowExtraSyntax(MessageSyntaxes.SpecialValueProperty | MessageSyntaxes.XamlBinding);
Then in Xaml you may use
cal:Message.Attach="[Event GotFocus] = [Action SelectTool({StaticResource contrastTool})]"

Related

How to create a If Else condition with xaml binding

I'm trying to create a XAML UI based on the condition.
<StackLayout Orientation="Horizontal">
<!--IF WorkEmailAddress != NULL && WorkEmailAddrress != ""-->
<!-- BEGIN IF -->
<Label Text="{Binding WorkEmailAddress}" Style="{StaticResource labelListItem}"></Label>
<Image HeightRequest="16" HorizontalOptions="End" VerticalOptions="Center" Source="arrow.png" Margin="0,0,15,0"></Image>
<!-- END IF -->
<!-- ELSE -->
<Label Text="Add new email" Style="{StaticResource labelLinkItem}">
</StackLayout>
Could one please let me know how to add a IF ELSE condition with in the XAML to dynamically create a UI based on the value returned from the backend.
You can't do this completely in XAML. Probably the best way to go is to add a bool property to your view model named HasWorkEmailAddress (I'm assuming you have one, and that's where WorkEmailAddress lives) which returns true if there's a non-null, non-empty value for WorkEmailAddress.
You can then bind the first label and Image's IsVisible property to this bool.
You can also create an InverseBooleanConverter, which will implement IValueConverter. The Convert method will simply take a bool and negate it, and return that value. Bind your second labels' IsVisible to the same bool, but specify the InverseBooleanConverter as the binding's Converter. It will then show only if the HasWorkEmailAddress returns false. The labels binding will look like this:
<Label IsVisible="{Binding HasWorkEmailAddress, Converter={StaticResource InverseBooleanConverter}}" />
If you don't want to write your own converter, one exists in the FreshEssentials Nuget package.
One last thing; if its possible for WorkEmailAddress to change while the page is being shown, you'll need to make sure you raise a PropertyChanged event for the HasWorkEmailAddress property, or your view will not change appropriately.

Tab icons in a Xamarin.Forms UWP TabbedPage?

When putting together a TabbedPage in Xamarin.Forms, how do I get UWP to use the page's Icon property?
It looks like UWP could support this just fine, if I configure my Forms attributes/files correctly.
Here's my TabbedPage XAML. The icons are all set up and working for iOS and Android, and even the on-page Image in UWP renders fine (meaning the files are likely in the project correctly).
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:tabbed"
x:Class="tabbed.MainPage">
<TabbedPage.Children>
<local:InitialPage Title="Tab1" Icon="star.png" />
<ContentPage Title="Tab2" Icon="gear.png">
<ContentPage.Content>
<StackLayout>
<Label Text="A nice label." />
<Image Source="star.png" /><!-- works here -->
</StackLayout>
</ContentPage.Content>
</ContentPage>
</TabbedPage.Children>
</TabbedPage>
I outlined how this is possible here http://depblog.weblogs.us/2017/07/12/xamarin-forms-tabbed-page-uwp-with-images/
In short, you need to change the default HeaderTemplate that is being used by UWP. But due to the way Xamarin forms is started, this is not straightforward.
So you need to inject a custom template into the resource dictionary.
Example project is up on Github here https://github.com/Depechie/XamarinFormsTabbedPageUWPWithIcons
Longer detail:
You need to supply your own TabbedPageStyle and switch out the one that Xamarin is using for their UWP rendering.
So the new style contains an Image where we data bind the Source to the Xamarin Icon property.
<Style x:Key="TabbedPageStyle2" TargetType="uwp:FormsPivot">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Vertical">
<Image Source="{Binding Icon, Converter={StaticResource IconConverter}}" Width="15" Height="15" />
<TextBlock Name="TabbedPageHeaderTextBlock" Text="{Binding Title}"
Style="{ThemeResource BodyTextBlockStyle}" />
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
The actual style switching is done in the App.Xaml.cs like this
((Style)this.Resources["TabbedPageStyle"]).Setters[0] = ((Style)this.Resources["TabbedPageStyle2"]).Setters[0];
You'll also need a converter to be sure the Image control understands the Icon source giving by Xamarin
public class IconConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value != null && value is Xamarin.Forms.FileImageSource)
return ((Xamarin.Forms.FileImageSource)value).File;
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
As it is currently, the UWP TabbedPage renderer does not use the Icon property at all, so getting tab icons will require a custom renderer. Even the official UWP samples don't actually seem to have this baked-in, requiring a custom UserControl.
The Android TabbedPageRenderer and iOS TabbedRenderer, and even the macOS TabbedPageRenderer, use the Icon property to adjust the tab UI, but the UWP renderer would need updating to make this work.

Xceed Datagrid won't bind to DataTemplate of Xceed control

I have the following DataTemplates defined. The TextBlock works the xctk:ShortUpDown does not. In fact whenever I use a control from another namespace it doesn't work (i.e. no data displayed or updated
<DataTemplate x:Key="intDataTemplate">
<TextBlock Text="{Binding StringFormat=\{0:F0\}}"/>
</DataTemplate>
<DataTemplate x:Key="hexDataTemplate">
<xctk:ShortUpDown ParsingNumberStyle="HexNumber"/>
</DataTemplate>
These are the column definitions. There is no CellEditorTemplate available.
<xcdg:Column FieldName="Coefficient" Width="75"
CellContentTemplate="{StaticResource hexDataTemplate}" ReadOnly="False"/>
<xcdg:Column FieldName="Measured" Width="75" CellHorizontalContentAlignment="Right"
CellContentTemplate="{StaticResource intDataTemplate}" />
There just doesn't seem to be a lot of example code out there. The columns are auto generated.
Any suggestions are appreciated.
The CellContentTemplate is for display purposes only. If you put a control meant for editing in it, such as a ShortUpDown, you will get weird results.
Editor controls should be defined in the CellEditor. Also, don't forget to set the CellEditorBinding to connect it to the underlying value.
<xcdg:CellEditor x:Key="hexCellEditor">
<xcdg:CellEditor.EditTemplate>
<DataTemplate>
<xctk:ShortUpDown Value="{xcdg:CellEditorBinding}" ParsingNumberStyle="HexNumber"/>
</DataTemplate>
</xcdg:CellEditor.EditTemplate>
</xcdg:CellEditor>
<xcdg:Column FieldName="Measured" CellEditor="{StaticResource hexCellEditor}" ... />

Silverlight4 Element Binding Weirdness

I'm a bit of a .net newbie and I've been working on my first big silverlight project. So pardon the lack of lingo and the length of the question. But my problem is as follows.
The project is being built according to the MVVM pattern ( in this case I'm using LightMVVM ). Most of the views contain ListBoxes. These listboxes need to handle multiple different types of data each of which has it's own visual look. After some poking around I decoded tp try this implementation for datatemplate selection:
http://silverscratch.blogspot.com/2010/04/changing-data-templates-at-run-time.html
Some of my items, however, have sub controls that need to talk to the viewmodel. From what I've been reading Commands with element bindings is the best ways to handle this.
So, for example:
<Grid x:Name="NavMainLayoutRoot" DataContext="{Binding Source={StaticResource NavMainViewModelDataSource}}" Margin="15,0,0,0">
....
<ListBox x:Name="MenuListBox" HorizontalAlignment="Left" Background="{x:Null}" BorderBrush="{x:Null}" Foreground="White" ItemsSource="{Binding Items}" ItemContainerStyle="{StaticResource MainNavigationButtonStyle}" Padding="0" VerticalAlignment="Top" >
<ListBox.RenderTransform>
<CompositeTransform/>
</ListBox.RenderTransform>
<ListBox.ItemTemplate>
<DataTemplate>
<xxxControls:SelectableContentControl TemplateName="{Binding Path=Type}" Content="{Binding Details}" IsTabStop="{Binding IsHitTestEnabled}">
<xxxControls:SelectableContentControl.Templates>
<DataTemplate>
<local:GenericItem />
</DataTemplate>
<DataTemplate x:Name="navbutton">
<local:MainNavItem />
</DataTemplate>
</xxxControls:SelectableContentControl.Templates>
</xxxControls:SelectableContentControl>
</DataTemplate>
</ListBox.ItemTemplate>
....
And MainNavItem, simplified is:
<Grid x:Name="NavItemRoot" VerticalAlignment="Top" Margin="0,0,0,0">
<Button Content="{Binding Label}" VerticalAlignment="Top" Style="{StaticResource MainNavItemButtonStyle}" HorizontalAlignment="Left" Margin="5,0" Command="{Binding DataContext.NavButtonClick, ElementName=NavMainLayoutRoot}"/>
</Grid>
The problem is that this didn't work. So for grins I went ahead and copy and pasted the code for the MainNavItem directly into the tag and like magic it started working.
Since I reuse a lot of these item templates all over the application, having them in nice contained external files is very nice and not something I want to give up.
(( Thinking about it, this example is not the best, suffice it to say that some of these data templates contain multiple controls and I can't just use selectedItem on the listbox to handle the selected events. ))
So any suggestions are welcome. What's the best practice here?
My first thought is that something in your MainNavItem user control is setting its DataContext to something else. If you don't set the DataContext it should automatically pick it up from the current item in your MenuListBox.
You can try creating a test value converter and putting a breakpoint in it to check what the data context is at runtime.
public class TestConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
Debug.WriteLine("TestConverter.Convert(value := {0}, targetType := {1}, parameter := {2}, culture := {3})",
value, targetType, parameter, culture);
return value; // put break point here to test data binding
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
Debug.WriteLine("TestConverter.ConvertBack(value := {0}, targetType := {1}, parameter := {2}, culture := {3})",
value, targetType, parameter, culture);
return value;
}
}
And modify your MainNavItem to look like this in order to break in the TestConverter at runtime.
<UserControl.Resources>
<ResourceDictionary>
<TestConverter x:Key="TestConverter" />
</ResourceDictionary>
</UserControl.Resources>
<Grid x:Name="NavItemRoot" DataContext="{Binding Converter={StaticResource TestConverter}}">
<Button Content="{Binding Path=Label, Converter={StaticResource TestConverter}}" />
</Grid>
This will help you determine the issue with data binding.
I suspect that the problem with your command is that you're using element-to-element data binding to attempt to bind to an element that is outside of the user control you're currently within. This won't work. Instead, try setting up your NavMainViewModelDataSource static resource in App.xaml, then you can bind directly to it from your user control.
<Button Content="{Binding Label}" Command="{Binding Path=NavButtonClick, Source={StaticResource NavMainViewModelDataSource}}" />

Silverlight 4 DataGrid LoadingRow event using MVVM-Light EventToCommand not firing?

I'm using the MVVM-Light EventToCommand to try and implement a pre-fetching mechanism from my ViewModel, using the sample code for EventToCommand that's posted on the MVVM Light codeplex site.
Unfortunately the command doesn't seem to fire, even though the MouseMove event which I used as my model does fire fine.
Am I missing something funky about the DataGrid LoaddingRow event that means this will never work?
Here's my XAML (with MouseMove event artificially added to the mix to prove out the basics):
<sdk:DataGrid x:Name="TaskDataGrid"
AutoGenerateColumns="True" CanUserReorderColumns="False"
CanUserResizeColumns="False" ItemsSource="{Binding UserTasks}">
<!-- LoadingRow="TaskDataGrid_LoadingRow"> -->
<i:Interaction.Triggers>
<i:EventTrigger EventName="LoadingRow">
<cmd:EventToCommand PassEventArgsToCommand="True"
Command="{Binding CheckForPrefetchCommand}" />
</i:EventTrigger>
<i:EventTrigger EventName="MouseMove">
<cmd:EventToCommand PassEventArgsToCommand="True"
Command="{Binding MoveMouseCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
etc.
Here's the code in my ViewModel:
public RelayCommand<MouseEventArgs> MoveMouseCommand
{
get;
private set;
}
public RelayCommand<DataGridRowEventArgs> CheckForPrefetchCommand
{
get;
private set;
}
and in the constructor for the ViewModel the following gets called
CheckForPrefetchCommand = new RelayCommand<DataGridRowEventArgs>(e =>
{
// Do stuff here
int rowCount = e.Row.GetIndex();
});
MoveMouseCommand = new RelayCommand<MouseEventArgs>(e =>
{
var element = e.OriginalSource as UIElement;
var point = e.GetPosition(element);
string temp = string.Format("Position: {0}x{1}", point.X, point.Y);
});
The code for the MouseMove is hit, the code for the LoadingRow isn't. What am I missing?
It's not the first time I hear this complaint about some DataGrid events. I didn't have time to look into it, but I think there is something wrong with that control. I will check with MSFT and get back to you.
Cheers,
Laurent
I have this problem with WPF.
After many attempts, i found a solution but it's still not logical for me.
the solution is to call the Event trigger two time for the same event LoadingRow.
it works for me with some things to adjust.
I don't know if my proposition can help Mr LBugnion to solve the problem, Any way i share it with you.
<i:Interaction.Triggers>
<i:EventTrigger EventName="LoadingRow">
<cmd:EventToCommand PassEventArgsToCommand="True"
Command="{Binding CheckForPrefetchCommand}" />
</i:EventTrigger>
<i:EventTrigger EventName="LoadingRow">
<cmd:EventToCommand PassEventArgsToCommand="True"
Command="{Binding CheckForPrefetchCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>

Resources