Static Binding works compiled but not under designer - wpf

The following code works fine when compiled but I can't get the Text="{x:Static local:SomeClass+Limits.Name}" to work in the designer. Any help in this regard would be greatly appreciated! Thanks....
namespace StaticTest
{
public class SomeClass
{
public static class Limits
{
public const string Name = "It Works!";
}
}
}
<Window
x:Class="StaticTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:StaticTest"
Title="StaticTest"
Height="146"
Width="296"
WindowStartupLocation="CenterScreen">
<TextBlock
Grid.Column="1"
Grid.Row="1"
Text="{x:Static local:SomeClass+Limits.Name}" />
</Window>

I got it. As it turns out you need to do something like the following:
using System;
namespace StaticTest
{
public abstract class AbstractViewModel<VM, LC>
where VM : new()
where LC : new()
{
public AbstractViewModel()
{
Limits = new LC();
}
static AbstractViewModel()
{
Instance = new VM();
}
public LC Limits { get; private set; }
public static VM Instance { get; private set; }
}
public class MainWindowViewModel :
AbstractViewModel<MainWindowViewModel, MainWindowViewModel.LimitsClass>
{
public class LimitsClass
{
public LimitsClass()
{
Lots = new MinMax<int>(1, 10);
}
public MinMax<int> Lots { get; private set; }
}
}
}
<Window
x:Class="StaticTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:StaticTest"
Title="StaticTest"
Height="146"
Width="296"
WindowStartupLocation="CenterScreen">
<Grid>
<TextBlock
Text="{Binding Source={x:Static local:MainWindowViewModel.Instance}, Path=Limits.Lots.MaxValue}" />
</Grid>
</Window>

You need a binding as #H.B. says:
<TextBlock Text="{Binding Source={x:Static local:SomeClass+Limits.Name}}"/>
The VS2010 designer can't handle this, but it works fine in VS11 beta.

Related

ArgumentNullException thrown from combobox in my custom activity

I have a simple custom activity demo of WF.
The XAML code:
<sap:ActivityDesigner x:Class="ActivityDesignerLibrary2.ActivityDesigner1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sap="clr-namespace:System.Activities.Presentation;assembly=System.Activities.Presentation"
xmlns:sapv="clr-namespace:System.Activities.Presentation.View;assembly=System.Activities.Presentation">
<Grid>
<ComboBox x:Name="comboBox"
ItemsSource="{Binding Path=ModelItem.Values}"
SelectedValue="{Binding Path=ModelItem.Value, Mode=TwoWay}"
HorizontalAlignment="Left" Margin="36,0,0,0" VerticalAlignment="Top" Width="120"/>
</Grid>
</sap:ActivityDesigner>
The code behide:
[Designer(typeof(ActivityDesignerLibrary2.ActivityDesigner1))]
public class Class1 : CodeActivity
{
public List<string> Values { get; set; }
public string Value { get; set; }
public Class1()
{
Values = new List<string>() { "V1", "V2", "V3"};
Value = "V2";
}
protected override void Execute(CodeActivityContext context)
{
}
}
When I drag this custom activity into a workflow, an error messagebox is popped up.
I found it's SelectedValue make the error, but is there anything error and how to fix it?

How to use Message.Attach to call methods inside another object

I have a view model which has another class set as its property. The another class contains implementations of ICommand as its properties. I would like to execute one of the commands on a double click.
Unfortunatelly, Caliburn.Micro raises an exception instead ("No target found for method Commands.Command.Execute.").
I've tried to search the net and read the documentation, but without any success.
How to do it correctly?
Note: In real application, the message might be attached to a grid view which might have a different DataContext than the view model containing the commands class.
The XAML:
<Window x:Class="WpfApplication8.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cal="http://www.caliburnproject.org">
<Grid>
<TextBox
cal:Message.Attach="[Event MouseDoubleClick]
= [Action Commands.Command.Execute(null)]" />
</Grid>
</Window>
The code-behind class:
namespace WpfApplication8
{
public partial class MainWindow
{
public Commands Commands { get; set; }
public MainWindow()
{
this.Commands =
new Commands { Command = new Command { MainWindow = this } };
this.InitializeComponent();
this.DataContext = this;
}
}
public class Commands
{
public Command Command { get; set; }
}
public class Command
{
public MainWindow MainWindow { get; set; }
public void Execute(object parameter)
{
this.MainWindow.Title = "Executed";
}
}
}
As #alik commented, complete solution is:
<Window x:Class="WpfApplication8.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cal="http://www.caliburnproject.org">
<Grid>
<TextBox
cal:Message.Attach="[Event MouseDoubleClick] = [Action Execute(null)]"
cal:Action.TargetWithoutContext="{Binding Commands.Command}"/>
</Grid>
</Window>

Binding data to ComboBox WPF

I am newbie to WPF, and needs help to bind data into the ComboBox. The xaml file contains the tag below.
<UserControl x:Class="SKAT.Postfordeler.Client.UI.View.ChooseInboxView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="42" d:DesignWidth="598">
<Grid>
<StackPanel Orientation="Horizontal">
<ComboBox Name="_currentInbox" Width="180" Margin="5" Height="22" DataContext="{Binding}" />
<Label Content="Et job kører allerede i denne indbakke (1500 ud af 1700 poster behandlet)" Name="_currentProcess" Margin="5" Height="25" />
</StackPanel>
</Grid>
//Inbox class , this class was implemented in seperate project
namespace SKAT.Postfordeler.Shared.DataTypes
{
[DataContract]
public class Inbox
{
[DataMember]
public String Id { get; set; }
[DataMember]
public String Folder { get; set; }
[DataMember]
public Rule Rules { get; set; }
}
}
//This code is located in the controller, the Activate method will fire when the MainWindow was executed
public void Activate()
{
var configuration = _configurationManager.GetConfiguration();// this method gets the xaml file settings
_chooseInboxView.FillInboxes(configuration.Inboxes); // Inboxes data binds to combobox
}
and in the View code behind, I created a method to bind the data which contains a type of list
public void FillInboxes(List<Inbox> inboxes)
{
DataContext = inboxes;
}
But it won't works,Any help please?
I assume your Inbox class consists of two properties (for simplicity), but there may be any number of them:
public class Inbox
{
public int ID { get; set; }
public string Text { get; set; }
}
You write a DataTemplate, for example:
<Grid.Resources>
<DataTemplate x:Key="InboxTemplate">
<WrapPanel>
<TextBlock Text="{Binding Path=ID}"/>
<TextBlock>:</TextBlock>
<TextBlock Text="{Binding Path=Text}"/>
</WrapPanel>
</DataTemplate>
</Grid.Resources>
Then correct your ComboBox declaration like:
<ComboBox Name="_currentInbox" Width="180" Margin="5" Height="22" ItemsSource="{Binding}" ItemTemplate="{StaticResource InboxTemplate}" />
Finally you set DataContext of your ComboBox to your List<Inbox>:
public void FillInboxes(List<Inbox> inboxes)
{
_currentInbox.DataContext = inboxes;
}
EDIT: As you've asked for a simpler solution, you can just override ToString() method of your Inbox class:
protected override string ToString()
{
return ID.ToString() + ":" + Text;
}
Instead of DataContext={Binding} you should have ItemsSource={Binding}.
The data context for any frameworkelement in the visual tree is by default {Binding}.
<ComboBox Name="_currentInbox"
SelectedItem="Hoved"
Width="180"
Margin="5"
Height="22"
DisplayMemberPath="Name"
ItemSource="{Binding}" />
Also for the combobox to display text of the items correctly I suppose you need DisplayMemberPath too. I assumed the property from Inbox class that you need to display is Name. Please replace with your relevant property name.
If your Inbox class is like,
public class Inbox
{
public int ID { get; set; }
public string Text { get; set; }
}
And if you do not want to change your xmal, the code behind method should be like this,
public void FillInboxes(List<Inbox> inboxes)
{
_currentInbox.DisplayMemberPath = "Text"; // To display the 'Text' property in the combobox dropdown
//_currentInbox.DisplayMemberPath = "ID"; // To display the 'ID' property in the combobox dropdown
_currentInbox.DataContext = inboxes;
}

wpf MVVM confusion

I have been looking at MVVM for the last couple days and thought i would try out a simple example to update a text box with a time. However i'm having a bit of trouble wrapping my head around this. I have a two projects in my Solution.. one i'm calling TimeProvider that right now is just returning Datetime event and another that is called E. Eventually i will use TimeProvider to provide a lot more information but i want to understand something simple first. Can some one please tell me why i'm not geting the gui to update.
namespace E.TimeProvider
{
public interface ITimeSource
{
void Subscribe();
event Action<Time> TimeArrived;
}
}
namespace E.TimeProvider
{
public class Time
{
private DateTime _earthDate;
public Time()
{
}
public Time(DateTime earthDate)
{
this._earthDate = earthDate;
}
public DateTime EarthDate
{
get { return _earthDate; }
set { _earthDate = value; }
}
}
}
namespace E.TimeProvider
{
public class TimeSource : ITimeSource
{
private const int TIMER_INTERVAL = 50;
public event Action<Time> TimeArrived;
private bool subscribe;
public TimeSource()
{
subscribe = false;
Thread timeGenerator = new Thread(new ThreadStart(GenerateTimes));
timeGenerator.IsBackground = true;
timeGenerator.Priority = ThreadPriority.Normal;
timeGenerator.Start();
}
public void Subscribe()
{
if (subscribe)
return;
subscribe = true;
}
private void GenerateTimes()
{
while (true)
{
GenerateAndPublishTimes();
Thread.Sleep(TIMER_INTERVAL);
}
}
private void GenerateAndPublishTimes()
{
DateTime earthDate = DateTime.Now;
Time time = new Time(earthDate);
TimeArrived(time);
}
}
}
Then i have my project E
xaml
<Window x:Class="E.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="300" Width="200" xmlns:my="clr-namespace:Exiled" WindowStyle="None" WindowStartupLocation="CenterScreen" ResizeMode="NoResize">
<Grid>
<my:TimeControl HorizontalAlignment="Left" x:Name="timeControl1" VerticalAlignment="Top" Height="300" Width="200" />
</Grid>
</Window>
<UserControl x:Class="E.TimeControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="200" Background="Black" Foreground="White">
<Grid>
<TextBlock Height="41" HorizontalAlignment="Left" Margin="12,31,0,0" Text="{Binding Path=EarthTime}" VerticalAlignment="Top" Width="176" FontSize="35" TextAlignment="Center" />
</Grid>
</UserControl>
and the rest
namespace E
{
public class TimeControlViewModel : DependencyObject
{
private readonly ITimeSource _source;
public ObservableCollection<TimeViewModel> Times { get; set; }
public TimeControlViewModel()
{
this.Times = new ObservableCollection<TimeViewModel>();
}
public TimeControlViewModel(ITimeSource source)
{
this.Times = new ObservableCollection<TimeViewModel>();
_source = source;
_source.TimeArrived += new Action<Time>(_source_TimeArrived);
}
public void Subscribe()
{
_source.Subscribe();
}
void _source_TimeArrived(Time time)
{
TimeViewModel tvm = new TimeViewModel();
tvm.Time = time;
}
}
}
namespace E
{
class SubscribeCommand
{
private readonly TimeControlViewModel _vm;
public SubscribeCommand(TimeControlViewModel vm)
{
_vm = vm;
}
public void Execute(object parameter)
{
_vm.Subscribe();
}
}
}
namespace E
{
public class TimeViewModel : DependencyObject
{
public TimeViewModel()
{
}
public Time Time
{
set
{
this.EarthDate = value.EarthDate;
}
}
public DateTime EarthDate
{
get { return (DateTime)GetValue(DateProperty); }
set { SetValue(DateProperty, value); }
}
// Using a DependencyProperty as the backing store for Date. This enables animation, styling, binding, etc...
public static readonly DependencyProperty DateProperty =
DependencyProperty.Register("EarthDate", typeof(DateTime), typeof(TimeViewModel), new UIPropertyMetadata(DateTime.Now));
}
}
You've got a few issues here:
You're not seeing an update, because the DataContext of your Window or UserControl is not set to the TimeViewModel instance you create.
Typically, ViewModel instances should not be DependencyObjects. Instead, implement INotifyPropertyChanged. This keeps them from having a dependency on WPF, but still allows them to work properly with MVVM.
I'd recommend reading through a detailed introduction to MVVM, such as the one I wrote here. In particular, you'll need to understand how templating works and the DataContext in order to use binding properly.
For a start it looks like you're binding to EarthTime:
Text="{Binding Path=EarthTime}"
but the property itself is called EarthDate
public DateTime EarthDate

Silverlight Control Toolkit TreeView not rendering items

I'm trying to build a SL app with a TreeView in it. Here's my XAML:
<UserControl xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Toolkit"
xmlns:tkwin="clr-namespace:System.Windows;assembly=System.Windows.Controls.Toolkit"
xmlns:basics="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SL.MyApp.Page"
Width="800" Height="600">
<controls:DockPanel>
<controls:TreeView Name="siteTree" controls:DockPanel.Dock="Left" Width="150">
<controls:TreeView.ItemTemplate>
<tkwin:HierarchicalDataTemplate ItemsSource="{Binding Children}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}"/>
</StackPanel>
</tkwin:HierarchicalDataTemplate>
</controls:TreeView.ItemTemplate>
</controls:TreeView>
<basics:TabControl controls:DockPanel.Dock="Right" TabStripPlacement="Top">
<basics:TabItem Header="Sites"></basics:TabItem>
<basics:TabItem Header="Lists"></basics:TabItem>
<basics:TabItem Header="Users"></basics:TabItem>
</basics:TabControl>
</controls:DockPanel>
</UserControl>
And the relevant codebehind:
namespace SL.MyApp
{
public partial class Page : UserControl
{
private ObservableCollection<WebDescriptor> _webHierarchy = new ObservableCollection<WebDescriptor>();
public Page(WebsSvc.WebsSoapClient websClient)
{
InitializeComponent();
siteTree.ItemsSource = _webHierarchy;
websClient.GetWebCollectionCompleted
+= new EventHandler<SL.SiteBuilder.WebsSvc.GetWebCollectionCompletedEventArgs>(websClient_GetWebCollectionCompleted);
websClient.GetWebCollectionAsync();
// TODO: some kind of spinner or progress bar needs to be started.
}
void websClient_GetWebCollectionCompleted(object sender, SL.SiteBuilder.WebsSvc.GetWebCollectionCompletedEventArgs e)
{
foreach (XElement xe in e.Result.Elements())
{
_webHierarchy.Add(ServiceObjectParser<WebDescriptor>.Parse(xe));
}
}
}
}
Update: The WebDescriptor class:
public class WebDescriptor
{
public string Title { get; set; }
public string Url { get; set; }
public List<WebDescriptor> Children { get; set; }
}
My problem is that nothing renders in the TreeView at all. I have verified that the results obtained in websClient_GetWebCollectionCompleted are valid and correct, but....nothing.
Any ideas?
in websClient_GetWebCollectionCompleted:
siteTree.ItemsSource = _webHierarchy;
Also, change your binding on the TextBlock in the Treeview to be {Binding Title}
After looking at the binding trace output, I finally realized I was trying to bind to a field instead of a property.
Doh!

Resources