Does Caliburn.Micro support design time data?
I tried out with following steps;
I created a simple hello world program. Where ShellViewModel is derived off of IShell. By running the sample program it does show hello word at run time. Since the view model is derived off of IShell I created a dummy class also derived off of IShell and used it as the design time instance.
public class SampleShellViewModel:IShell
{
#region IShell Members
public string HelloWorld
{
get { return "Hello World"; }
}
#endregion
}
in the view I added the design time context as follows
<UserControl x:Class="HelloWorld.ShellView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:sampleData="clr-namespace:HelloWorld"
d:DesignHeight="287" d:DesignWidth="518"
>
<Grid Background="White" d:DataContext="{d:DesignInstance sampleData:SampleShellViewModel, IsDesignTimeCreatable=True}">
<TextBlock Name="HelloWorld"
VerticalAlignment="Center"
HorizontalAlignment="Center"
FontSize="20" />
</Grid>
Is there anything I a missing?
Thanks
Please, look at Example of Caliburn Micro design data. by Derek Beattie.
Applying the Bind.AtDesignTime should do the trick.
<UserControl
xmlns:cal="http://www.caliburnproject.org"
cal:Bind.AtDesignTime="True"
>
<!-- etc -->
</UserControl>
Quoting Graeme's comment, since it answered my question.
Okay your d:DataContext="blah... code is perfect you still need Text={Binding HelloWorld} for blend to access the data (Id completely glossed over looking at that part), Blend doesn't run the xaml through the Caliburn convention binder. It needs to be explicitly set.
– Graeme Bradbury Jul 22 at 15:14"
Related
I have a TextBlock with its HorizontalAlignment property set to Stretch, and would like it to display different text based on different values of its width, e.g.:
VSTS if width < 70
VS Team Services if 70 <= width < 150
Visual Studio Team Services if 150 < width
This behavior can be achieved using the SizeChanged event of the TextBlock:
<TextBlock HorizontalAlignment="Stretch" TextTrimming="CharacterEllipsis" SizeChanged="VisualStudioTeamServicesTextBlock_SizeChanged"/>
private void VisualStudioTeamServicesTextBlock_SizeChanged(object sender, SizeChangedEventArgs e)
{
if (e.NewSize.Width < 70)
(sender as TextBlock).Text = "VSTS";
else if (e.NewSize.Width < 150)
(sender as TextBlock).Text = "VS Team Services";
else
(sender as TextBlock).Text = "Visual Studio Team Services";
}
However I'm looking for a more elegant XAML-based solution, something that would look like:
<TextBlock HorizontalAlignment="Stretch" TextTrimming="CharacterEllipsis">
<TextBlock.Triggers>
<Trigger MaxWidth="70">
<Setter Property="Text" Value="VSTS"/>
</Trigger>
<Trigger MaxWidth="150">
<Setter Property="Text" Value="VS Team Services"/>
</Trigger>
<Trigger MinWidth="150">
<Setter Property="Text" Value="Visual Studio Team Services"/>
</Trigger>
</TextBlock.Triggers>
</TextBlock>
I guess it could be done in several different ways (using style triggers or visual state manager or maybe even some 3rd party library), but since I'm not an expert, I simply ask which would be the simplest for the given task. Working sample is much appreciated.
Adaptive triggers would be the best solution to your problem, since everything would be XAML-based, but unfortunately the visual states can only be applied based on the window properties.
By subclassing the StateTriggerBase class and you could expose Adaptive Triggers to a couple of aditional triggers situations such as Internet Connection, but accessing a Run-Time dependency object from there seems unfeasible, at least for me (I ain't no expert either).
Creating your own visual state and jumping between states depending on your Control's dimension would be another possible solution.
But all of these solutions share the same behind-logic, which is: somewhere there is code-behind which is tracking the dependency properties and puppeteering the outcome.
Might this be an XY Problem ?
I made a really lackluster solution where I created my own UserControl, and created a custom dependency property, which could share 3 states: Small, Medium, Big. But after that I realized that the solution which I had envisioned was not as useful as I had in mind.
In theory, there's a control which exposed a custom dependency property, which is set whenever the control size has changed (once again we cannot run from the Event logic). Only in the dependency property setter, I actually set the Text for our TextBox. The property setter is defined as private, so there's no way you can externally set this property value of this user control.
But you can read it, just like it's expected from a dependency property.
The purpose of this solution was honestly more about forcing me to explore the subject of creating custom controls, dependency properties or attached properties, rather than making something that would be of extreme value. But hopefully you might take some value from this,
UserControl:
Code-Behind
public sealed partial class TextBox : UserControl
{
public enum TextBoxOptions
{
Small = 0,
Medium = 1,
Big = 2
}
public static readonly DependencyProperty TrackingWidthProperty =
DependencyProperty.Register(
"Dependency",
typeof(TextBoxOptions),
typeof(TextBox),
new PropertyMetadata(false)
);
public TextBoxOptions TrackingWidth
{
get
{
return (TextBoxOptions)GetValue(TrackingWidthProperty);
}
private set
{
if (value == TextBoxOptions.Small) TextBoxRoot.Text = "VSTS";
else if (value == TextBoxOptions.Medium) TextBoxRoot.Text = "VS Team Services";
else TextBoxRoot.Text = "Visual Studio Team Services";
SetValue(TrackingWidthProperty, value);
}
}
public TextBlock()
{
this.InitializeComponent();
this.DataContext = this;
TextBoxRoot.SizeChanged += TextBoxRoot_SizeChanged;
}
private void TextBoxRoot_SizeChanged(object sender, SizeChangedEventArgs e)
{
if (TextBoxRoot.ActualWidth < 600) TrackingWidth = TextBoxOptions.Small;
else if (TextBoxRoot.ActualWidth < 800) TrackingWidth= TextBoxOptions.Medium;
else TrackingWidth = TextBoxOptions.Big;
}
}
XAML:
<UserControl
x:Class="VisualStateTrigger.TextBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:VisualStateTrigger"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid>
<TextBox x:Name="TextBoxRoot"/>
</Grid>
</UserControl>
Outside of UserControl:
<Page
x:Class="VisualStateTrigger.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:VisualStateTrigger"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="200"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="150"/>
</Grid.ColumnDefinitions>
<local:TextBlock Grid.Column="1" Grid.Row="1" x:Name="myTextBox" HorizontalAlignment="Stretch"/>
</Grid>
</Grid>
</Page>
Result
Conclusion:
I was having problems for low width dimensions, that you defined, that's why the numbers are bumped up.
Defining the Data Context like I did on the user control is a mistake from what I've gathered around, but this is working ...
Creating your own control lets you encapsulate all additional logic in the control itself. If you needed a bunch of this elements to share the same kind of behavior, you don't need to expose multiple event-handlers or create a common location for them to have access for those handlers, since it is actually part of their implementation.
And for a couple of more complex scenarios, I can imagine that exposing a couple of Dependency Properties might be extremely useful. Even for this situation, checking out TrackingWidth Dependency Property would tell you what's the current visual state of your control, and maybe that could be important for a couple of very specific situations.
I have a ListView with this item template:
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<views:ProjectListEntry />
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
ProjectListEntry is fairly complex and is used in another ListView, so I have it in its own file. I've set it up like this:
<ContentView
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
...
BindingContext="{x:Static vms:DesignTimeData.ProjectListEntryVm}">
As you can see, to get binding Intellisense (using ReSharper), I tried to set BindingContext to a static member on the DesignTimeData class. This works fine for my Pages (where I replace the BindingContext at runtime), but for ContentViews used in ListViews, the ContentView's BindingContext seems to be inherited (from the ViewCell, I guess). This means that the explicit BindingContext on my ContentView will actually override the BindingContext set on the ViewCell by the ListView, and all my list elements will reflect the static design-time data at runtime. But if I remove the BindingContext, I get no intellisense for the members I bind to inside the ContentView file.
Is there a simple way to get Intellisense for bindings in a ContentView like this?
(As mentioned, I can't inline the ContentView in the ListView definition, because the ContentView is fairly complex and used in several lists. I also can't use some kind of VM locator, because although I'm using bindings, I'm not using "full" MVVM - I'm using a Redux-like architecture instead. And I guess a VM locator wouldn't work for this case anyway for the same reasons the above doesn't work.)
(Cross-posted from the Xamarin Forums where I didn't get any reply.)
This solution seems to work fine. In short: Add
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
and use d:DataContext instead of BindingContext. Going from the example above, it should look like this:
<ContentView
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
...
BindingContext="{x:Static vms:DesignTimeData.ProjectListEntryVm}">
This leads to working binding intellisense from ReSharper and does not cause issues when run.
I am a huge fan of the browser on Windows phone and I want to port a similar bottom bar to my app. Right now, I am using a standard CommandBar.
<Page.BottomAppBar>
<CommandBar>
<AppBarButton Icon="Go" Click="Go"/>
<CommandBar.SecondaryCommands>
<AppBarButton Icon="Setting" Label="Settings" Click="ShowSettings"/>
</CommandBar.SecondaryCommands>
</CommandBar>
</Page.BottomAppBar>
As this wastes screen space, I really want to make use of the remaining space of the bar to add something like app status (in place of the address bar of Edge/IE), something like download/upload progress. Unfortunately, the CommandBar does not allow introducing things like TextBlock or ProgressRing. To make use of those controls, we need to change to an AppBar instead. But then, I cannot use the features of CommandBar like the adding 3 dots buttons to open up the hidden buttons.
Is there an easy way to achieve this i.e. combining the flexibility of AppBar and the 3-dot feature of CommandBar?
CommandBar only accept the control that inherit ICommandBarElement interface.
We can create one UserControl which inherit ICommandBarElement, simply did a small test without optimize the code, take a look to see if it helps:
public sealed partial class MyUserControl1 : UserControl, ICommandBarElement
{
public MyUserControl1()
{
this.InitializeComponent();
}
private bool _IsCompact = true;
bool ICommandBarElement.IsCompact
{
get
{
return _IsCompact;
}
set
{
_IsCompact = value;
}
}
}
Also the UserControl XAML:
<UserControl
x:Class="App10.MyUserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App10"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignWidth="400" Height="38.027">
<Grid>
<TextBlock Foreground="DarkBlue">asdsadasdasdasdasda</TextBlock>
</Grid>
And then we use the userControl in the CommandBar, here we go:
http://i.stack.imgur.com/Bgug9.png
Note: please further optimize it for instance register some Text dependency properties to enable accept the data binding.
Per the documentation on MSDN you can use the CommandBar.Content property which corresponds to the empty area to the side of any primary commands. To alter the alignment of the content you'd need to change the CommandBar.HorizontalContentAlignment property.
<CommandBar HorizontalContentAlignment="Stretch">
<AppBarButton Icon="Go" Click="Go"/>
<CommandBar.SecondaryCommands>
<AppBarButton Icon="Setting" Label="Settings" Click="ShowSettings"/>
</CommandBar.SecondaryCommands>
<CommandBar.Content>
<Grid>
<TextBox HorizontalAlignment="Stretch"
VerticalAlignment="Top"
Margin="12,8"/>
</Grid>
</CommandBar.Content>
</CommandBar>
And as of Win10 the recommendation is to place the CommandBar inline instead of using the Page.TopAppBar or Page.BottomAppBar properties. The one scenario in which you may still want to use the Page.BottomAppBar property is to ensure the CommandBar remains visible when the software keyboard appears.
I'm trying to figure out the RepeaterView in Xamarin Forms Labs.
THE BACKGROUND
I have a simple entity called Entry that has property called Notes
class Entry
{
public string Notes { get; set; }
}
In the common PCL, I've inherited from the RepeaterView to make it non-generic.
class EntryRepeater : Xamarin.Forms.Labs.Controls.RepeaterView<MyKids.Core.Entities.Entry>
{
}
And the XAML of the page where I'm trying to use the repeater looks like this
<rep:EntryRepeater ItemsSource="{Binding Entries}">
<rep:EntryRepeater.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<StackLayout>
<Label Text="{Binding Notes}" />
</StackLayout>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</rep:EntryRepeater.ItemTemplate>
</rep:EntryRepeater >
where Entries is an ObservableCollection.
THE ISSUE
The problem is that the binding in the DataTemplate seems to point to the main model and not to one item in the collection. BUT it is repeated the correct number of times.
[0:] Binding: 'Notes' property not found on 'MyApp.ViewModels.EntryListViewModel', target property: 'Xamarin.Forms.Label.Text'
To circle back to this question, this was actually an error in earlier versions of Xlabs. It's now fixed and the code above does work.
How do I retrieve the value (Int32.MaxValue) from the static extension:
<x:Static
x:Key="TooltipTimeout"
Member="s:Int32.MaxValue"
/>
...
<blablalba TooltipService.ShowDuration="{StaticResource TooltipTimeout}"/> <-- this does not work by the way
Methinks you're doing something else wrong. Slap this in kaxaml:
<Page
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<x:Static x:Key="Derp" Member="sys:Int32.MaxValue"/>
</Page.Resources>
<Grid>
<TextBlock
ToolTipService.ShowDuration="{StaticResource Derp}"
ToolTip="Derp" Text="Herp" />
</Grid>
</Page>
Mod tested, mother approved.
If I had to guess, I think you're not defining your xml namespace for Int32 correctly.
In WPF, You can access static member directly, like this,
<TextBlock TooltipService.ShowDuration="{x:Static s:Int32.MaxValue}"/>
However, you cannot do the same in Silverlight, as it wouldn't work. In silveright, you've to write a wrapper class, like this,
public class StaticMemberAccess
{
public int Int32Max { get { return Int32.MaxValue; } }
//define other wrapper propeties here, to access static member of .Net or your classes
}
Then do this in XAML,
<UserControl.Resources>
<local:StaticMemberAccess x:Key="SMA"/>
</UserControl.Resources>
<TextBlock TooltipService.ShowDuration="{Binding Source={StaticResource SMA}, Path=Int32Max}"/>
.
Try to bind to your resource by setting it as the Source of your binding:
{Binding Source={StaticResource TooltipTimeout}}