I'm trying to get an object's current VisualState. I found an answer on SO that this isn't possible, and another blog elsewhere that I should be able to get these like this:
var currentState = VisualStateManager.GetVisualStateGroups(ContainerGrid);
However curentState doesn't seem to get anything. What am I doing wrong?
I found this answer worked better for me, as I didn't need anything external: Silverlight: VisualStateManager.GetVisualStateGroups doesn't, How can I get them?
The WinRT XAML Toolkit has this extension method - AwaitableUI.ControlExtensions.GoToVisualStateAsync() that finds the storyboard for visual state transition using the method you mentioned (VisualStateManager.GetVisualStateGroups()) and awaits its completion after calling the regular VisualStateManager.GoToState() method. It has worked fine for me so far. The only thing of note is that you need to call GetVisualStateGroups() on the element that specifies the visual state groups, so in most cases you might need to dig into the control template's visual tree since that is where they are usually defined - somewhere deeper in the template than the actual logical control.
Here is my full sample class:
using System;
using System.Linq;
using System.Threading.Tasks;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media.Animation;
namespace WinRTXamlToolkit.AwaitableUI
{
/// <summary>
/// Extension methods for Control class.
/// </summary>
public static class ControlExtensions
{
#region GoToVisualStateAsync()
/// <summary>
/// Goes to specified visual state, waiting for the transition to complete.
/// </summary>
/// <param name="control">
/// Control to transition.
/// </param>
/// <param name="visualStatesHost">
/// FrameworkElement that defines the visual states
/// (usually the root of the control's template).
/// </param>
/// <param name="stateGroupName">
/// Name of the state group
/// (speeds up the search for the state transition storyboard).
/// </param>
/// <param name="stateName">
/// State to transition to.
/// </param>
/// <returns>
/// Awaitable task that completes when the transition storyboard completes.
/// </returns>
/// <remarks>
/// If a state transition storyboard is not found - the task
/// completes immediately.
/// </remarks>
public static async Task GoToVisualStateAsync(
this Control control,
FrameworkElement visualStatesHost,
string stateGroupName,
string stateName)
{
var tcs = new TaskCompletionSource<Storyboard>();
Storyboard storyboard =
GetStoryboardForVisualState(visualStatesHost, stateGroupName, stateName);
if (storyboard != null)
{
EventHandler<object> eh = null;
eh = (s, e) =>
{
storyboard.Completed -= eh;
tcs.SetResult(storyboard);
};
storyboard.Completed += eh;
}
VisualStateManager.GoToState(control, stateName, true);
if (storyboard == null)
{
return;
}
await tcs.Task;
}
#endregion
#region GetStoryboardForVisualState()
/// <summary>
/// Gets the state transition storyboard for the specified state.
/// </summary>
/// <param name="visualStatesHost">
/// FrameworkElement that defines the visual states
/// (usually the root of the control's template).
/// </param>
/// <param name="stateGroupName">
/// Name of the state group
/// (speeds up the search for the state transition storyboard).
/// </param>
/// <param name="stateName">
/// State to transition to.
/// </param>
/// <returns>The state transition storyboard.</returns>
private static Storyboard GetStoryboardForVisualState(
FrameworkElement visualStatesHost,
string stateGroupName,
string stateName)
{
Storyboard storyboard = null;
var stateGroups = VisualStateManager.GetVisualStateGroups(visualStatesHost);
VisualStateGroup stateGroup = null;
if (!string.IsNullOrEmpty(stateGroupName))
{
stateGroup = stateGroups.FirstOrDefault(g => g.Name == stateGroupName);
}
VisualState state = null;
if (stateGroup != null)
{
state = stateGroup.States.FirstOrDefault(s => s.Name == stateName);
}
if (state == null)
{
foreach (var group in stateGroups)
{
state = group.States.FirstOrDefault(s => s.Name == stateName);
if (state != null)
{
break;
}
}
}
if (state != null)
{
storyboard = state.Storyboard;
}
return storyboard;
}
#endregion
}
}
This is how I call it:
await this.GoToVisualStateAsync(_layoutRoot, PopupStatesGroupName, OpenPopupStateName);
Where this is my InputDialog control and _layoutRoot is a part of its template defined like this:
<Setter
Property="Template">
<Setter.Value>
<ControlTemplate
TargetType="controls:InputDialog">
<Grid
x:Name="LayoutRoot"
Background="{TemplateBinding BackgroundScreenBrush}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup
x:Name="PopupStates">
<VisualState
x:Name="OpenPopupState">
<Storyboard>
...
Once you extract that visual state group you can get the last set state by getting stateGroup.CurrentState.
In UWP XAML just name de VisualStateGroup:
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="PopupStates">
<VisualState x:Name="Mobile">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0"/>
</VisualState.StateTriggers>
and you get the name using:
PopupStates.CurrentState.Name
Related
I'm trying to access a scaling factor in a viewModel through my CustomNumericLabelProvider.
I'm not quite sure what the best approach is, but I figured I might be able to access it through the parent axis if I used the Init(IAxis parentAxis) method which was shown in the LabelProvider documentation. I've given that a try, but now I'm getting an error telling me that "There is no suitable method for override".
If I comment out the Init() method, CustomNumericLabelProvider works great (with a hard-coded scaling factor).
Any idea why I'm receiving this error message? Or what another good approach would be to gain access to the scaling factor in my viewModel?
Note: I've also tried passing the viewModel into a custom constructor for the label provider (I was able to do something like this with viewportManager), however that didn't seem to work.
Here's the code (With the custom constructor, although I get the same error message without it)
public class CustomNumericLabelProvider : SciChart.Charting.Visuals.Axes.LabelProviders.NumericLabelProvider
{
// Optional: called when the label provider is attached to the axis
public override void Init(IAxis parentAxis) {
// here you can keep a reference to the axis. We assume there is a 1:1 relation
// between Axis and LabelProviders
base.Init(parentAxis);
}
/// <summary>
/// Formats a label for the axis from the specified data-value passed in
/// </summary>
/// <param name="dataValue">The data-value to format</param>
/// <returns>
/// The formatted label string
/// </returns>
public override string FormatLabel(IComparable dataValue)
{
// Note: Implement as you wish, converting Data-Value to string
var converted = (double)dataValue * .001 //TODO: Use scaling factor from viewModel
return converted.ToString();
// NOTES:
// dataValue is always a double.
// For a NumericAxis this is the double-representation of the data
}
}
I would propose passing the scaling factor into the constructor of the CustomNumericLabelProvider, and instantiating it in your viewmodel.
So your code becomes
public class CustomNumericLabelProvider : LabelProviderBase
{
private readonly double _scaleFactor;
public CustomNumericLabelProvider(double scaleFactor)
{
_scaleFactor = scaleFactor;
}
public override string FormatLabel(IComparable dataValue)
{
// TODO
}
public override string FormatCursorLabel(IComparable dataValue)
{
// TODO
}
}
public class MyViewModel : ViewModelBase
{
private CustomNumericLabelProvider _labelProvider = new CustomNumericLabelProvider(0.01);
public CustomNumericLabelProvider LabelProvider { get { return _labelProvider; } }
}
And you then bind to it as follows
<s:NumericAxis LabelProvider="{Binding LabelProvider}"/>
Assuming the datacontext of NumericAxis is your viewmodel.
Please be advised in SciChart v5 there will be new APIs for AxisBindings (similar to SeriesBinding) for dynamically creating axis in ViewModel. This will make dynamic axis in MVVM much easier. You can take SciChart v5 for a test-drive by accessing our WPF Chart Examples here.
Actually LonglistSelector bind with a dynamic list of image uri. i need to display loading indicator for each image until image loaded. If anybody knows how to make it done please help me Immediately. Thanks in advance.
You will have to provide a list of objects that know the following:
Image URL
Loading Indicator
The LonglistSelector Item Template would then display the Loading animation as long as LoadingIndicator is true. As soon as it becomes false, it would display the image.
This can be achieved using the Visibility property and a BooleanToVisibilityConverter class.
The model stated on top must implement INotifyPropertyChanged for the loading indicator to get the automatic UI refresh for each item as soon as it got changed.
Your model would look like this. The refered class BindableBase is a class from Microsoft which can be found here: http://msdn.microsoft.com/en-US/en-en/library/windows/apps/xx130657.aspx
public class ImageViewModel : BindableBase
{
/// <summary>
/// No need to use SetProperty here, because this parameter is not bound against any UI control
/// which would need a refresh
/// </summary>
public string ImageUrl { get; set; }
private bool isLoading;
/// <summary>
/// Reflects loading status of the underlying tile.
/// </summary>
public bool IsLoading
{
get { return isLoading; }
set { SetProperty(ref isLoading, value); }
}
private ImageSource imageContent;
/// <summary>
/// Reflects image which shall be displayed.
/// </summary>
public ImageSource ImageContent
{
get { return imageContent; }
set { SetProperty(ref imageContent, value); }
}
}
Your UI would bind against a list of those model entities and display the loading animation when isLoading is true, else the image. For this, you can use the BooleanToVisibilityConverter class which is most of the time created together with new projects. But you may search for the class online.
Now when your page is loaded, you iterate through your list of items and start downloading the image. Once you have downloaded it, replace the "ImageContent" with the actual image and set IsLoading to false. Your UI will then display the image and hide the loading animation because both properties are notitied to the UI.
Your data template would look something like this:
<DataTemplate x:Key="itemTemplateLongListSelector">
<StackPanel Width="230" Height="290" Margin="4,4">
<Image Width="230" Height="290" Stretch="UniformToFill" Visibility="{Binding IsLoading, Converter={StaticResource BooleanNegationToVisibilityConverter}}">
<Image.Source>
<BitmapImage UriSource="{Binding ImageSource}"/>
</Image.Source>
</Image>
<TextBlock Text="Loading..." Visibility="{Binding IsLoading, Converter={StaticResource BooleanToVisibilityConverter}}"/>
</StackPanel>
</DataTemplate>
The converter classes needed:
public sealed class BooleanNegationToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return (value is bool && (bool)value) ? Visibility.Collapsed : Visibility.Visible;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value is Visibility && (Visibility)value == Visibility.Collapsed;
}
}
public sealed class BooleanToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return (value is bool && (bool)value) ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value is Visibility && (Visibility)value == Visibility.Visible;
}
}
Both need to be declared in your App.xaml resource dictionary section:
<common:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
<common:BooleanNegationToVisibilityConverter x:Key="BooleanNegationToVisibilityConverter"/>
"common" is defined in App.xaml on top:
<Application
...
xmlns:common="clr-namespace:YourProject.Path.To.Converter.Classes"
...>
I am trying create UserControl with below requirements.
Usercontrol contains a gridview and in side gridview, I need to add a button element. So, the idea is :- if usercontrol is used in any other page by providing a collection to ItemSource then list of buttons should be generated and Button content value should be one of the property value of type present in Itemsource collection.
I am pretty newbie to windows store app programming. I am trying to expose the gridview ItemSources property by creating dependency property so that ObservableCollection of any type can be mapped and trying expose a dependency property to bind to button content property. but not able to achieve the same. I would really appreciate if you could point to a sample application doing the same.
Thanks a lot in advance.
here is a small sample (i hope that's what you wanna do)...
EDIT: I finally edited my answer to provide the property which takes the property path. IF ANYONE HAS ANOTHER SOLUTION FOR THIS QUESTION, PLEASE LET ME KNOW!
Add a dependency property for the binding path:
First we create a dummy model which provides the title for our buttons:
public class SampleModel
{
public string Title { get; set; }
}
Then, the usercontrol. The important thing here is the ItemsSource-Binding (ElementName = UserControl). Otherwise you'll bind to the UserControlItemsSource in the Parent-DataContext.
EDIT: The button has changed since my last answer!
<UserControl
x:Class="StackOverflow.ListUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:StackOverflow"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400"
x:Name="SampleUserControl">
<Grid>
<ListView ItemsSource="{Binding UserControlItemsSource, ElementName=SampleUserControl}" Background="DeepSkyBlue" SelectionMode="None">
<ListView.ItemTemplate>
<DataTemplate>
<Button Loaded="FrameworkElement_OnLoaded"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</UserControl>
... and the usercontrol's code-behind including the UsercontrolItemsSource:
EDIT: i added the dependency property BindingPropertyPath and the FrameworkElement_OnLoaded method since my last answer.
public sealed partial class ListUserControl : UserControl
{
public ObservableCollection<SampleModel> UserControlItemsSource
{
get { return (ObservableCollection<SampleModel>)GetValue(UserControlItemsSourceProperty); }
set { SetValue(UserControlItemsSourceProperty, value); }
}
// Using a DependencyProperty as the backing store for UserControlItemsSource. This enables animation, styling, binding, etc...
public static readonly DependencyProperty UserControlItemsSourceProperty =
DependencyProperty.Register("UserControlItemsSource", typeof(ObservableCollection<SampleModel>), typeof(ListUserControl), new PropertyMetadata(null));
public string BindingPropertyPath
{
get { return (string)GetValue(BindingPropertyPathProperty); }
set { SetValue(BindingPropertyPathProperty, value); }
}
// Using a DependencyProperty as the backing store for BindingPropertyPath. This enables animation, styling, binding, etc...
public static readonly DependencyProperty BindingPropertyPathProperty =
DependencyProperty.Register("BindingPropertyPath", typeof(string), typeof(ListUserControl), new PropertyMetadata(string.Empty));
public ListUserControl()
{
this.InitializeComponent();
}
private void FrameworkElement_OnLoaded(object sender, RoutedEventArgs e)
{
Button button = sender as Button;
Binding contentBinding = new Binding();
contentBinding.Path = new PropertyPath(this.BindingPropertyPath);
button.SetBinding(Button.ContentProperty, contentBinding);
}
}
Now we add the usercontrol to our main page (ListPageHost):
EDIT: Set the new dependency property BindingPropertyPath to the name of the property of the ItemsSource that you wanna use for the button.
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Button Grid.Row="0" Content="Add Item to ItemsSource" Click="ButtonBase_OnClick"></Button>
<local:ListUserControl Grid.Row="1" UserControlItemsSource="{Binding SampleCollection}" BindingPropertyPath="Title"/>
</Grid>
In the mainpage's code-behind, we declare our mainpage-viewmodel (ListPageHostViewModel):
public class ListPageHostViewModel
{
private readonly ObservableCollection<SampleModel> _sampleCollection = new ObservableCollection<SampleModel>();
public ObservableCollection<SampleModel> SampleCollection
{
get { return _sampleCollection; }
}
}
... and the MainPage's (ListPageHost) code behind:
public sealed partial class ListPageHost : Page
{
public ListPageHost()
{
this.InitializeComponent();
this.DataContext = new ListPageHostViewModel();
}
/// <summary>
/// Invoked when this page is about to be displayed in a Frame.
/// </summary>
/// <param name="e">Event data that describes how this page was reached. The Parameter
/// property is typically used to configure the page.</param>
protected override void OnNavigatedTo(NavigationEventArgs e)
{
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
var vm = this.DataContext as ListPageHostViewModel;
if (vm != null)
{
vm.SampleCollection.Add(new SampleModel() { Title = string.Format("new item {0}", DateTime.Now.Ticks)});
}
}
}
Hope that's what you're looking for. If you have any questions - let me know.
Regards, Alex
I have the following code:
public class MessageEndpoint : IConfigureThisEndpoint, AsA_Server, IWantCustomInitialization
{
private IWindsorContainer _container;
public void Init()
{
_container = new WindsorContainer();
var bus = (IBus)Configure.With()
.CastleWindsorBuilder(_container)
.MsmqTransport()
.PurgeOnStartup(true);
_container.Register(Component.For<IWindsorContainer>().Instance(_container));
_container.Install(FromAssembly.This());
}
}
elsewhere in the code i am using windsor installers i.e.:
public class StorageConfiginstaller : IWindsorInstaller
{
/// <summary>
/// Performs the installation in the <see cref="T:Castle.Windsor.IWindsorContainer"/>.
/// </summary>
/// <param name="container">The container.</param><param name="store">The configuration store.</param>
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Component.For<IStoreEvents>().Instance(BuildEventStore(container.Kernel)).LifeStyle.Singleton);
container.Register(Component.For<IDetectConflicts>().ImplementedBy<ConflictDetector>());
container.Register(Component.For<IRepository>().ImplementedBy<EventStoreRepository>());
container.Register(Component.For<IConstructAggregates>().ImplementedBy<AggregateFactory>());
container.Register(Component.For<IBus>().ImplementedBy<UnicastBus>());
}
private static IStoreEvents BuildEventStore(IKernel container)
{
return Wireup.Init()
.UsingRavenPersistence("EventStore", new DocumentObjectSerializer())
.UsingAsynchronousDispatcher()
.PublishTo(new DelegateMessagePublisher(c => DispatchCommit(container, c)))
.Build();
}
private static void DispatchCommit(IKernel container, Commit commit)
{
var publisher = container.Resolve<IBus>();
publisher.Publish(commit.Events.Select(e => (IMessage)e.Body).ToArray());
}
}
problem is - the bus isn't registered in the container? How do i get it so the bus is registered?
*******update********
this doesn't work?!
_container = new WindsorContainer();
var c = Configure.With()
.CastleWindsorBuilder(_container)
.MsmqTransport()
.PurgeOnStartup(true);
var bus = _container.Resolve<IBus>();
I've checked with the Pub/Sub sample where Subscriber2 is already set up to use Windsor as its container, added a constructor injected IBus property, and everything works as expected (on version 2.5).
Consider not passing in the _container and just letting NServiceBus set that up for you.
I have a soap web service in my web layer (s#arp architecture) which uses a service like this:
public ReportWebService(IReportService ReportService)
{
Check.Require(ReportService != null, "ReportService may not be null");
this.ReportService = ReportService;
}
Can someone please remind me how/where I configure the injection of the implementation for IReportService again?
Thanks.
Christian
The short answer is: Just put ReportService into yourProject.ApplicationServices and it will be injected.
The long answer is: In yourProject.Web in Global.asax you will find the method InitializeServiceLocator(). This calls the static method AddComponents on ComponentRegistrar.
ComponentRegistrar is located in yourProject.web/CastleWindsor. In there you will find
public static void AddComponentsTo(IWindsorContainer container)
{
AddGenericRepositoriesTo(container);
AddCustomRepositoriesTo(container);
AddApplicationServicesTo(container);
container.AddComponent("validator",
typeof(IValidator), typeof(Validator));
}
If you look at AddApplicationServicesTo you can see that is registers all types in yourProject.ApplicationServices (.WithService.FirstInterface()):
private static void AddApplicationServicesTo(IWindsorContainer container)
{
container.Register(
AllTypes.Pick()
.FromAssemblyNamed("NewittsStore.ApplicationServices")
.WithService.FirstInterface());
}
Here is from ComponentRegistrar.cs:
/// <summary>
/// The add application services to.
/// </summary>
/// <param name="container">
/// The container.
/// </param>
private static void AddApplicationServicesTo(IWindsorContainer container)
{
container.Register(AllTypes.Pick().FromAssemblyNamed("MyAssembly.ApplicationServices").WithService.FirstInterface());
}
and here is from the a service
private readonly IDocumentManagementService _client;
public DocumentService(IDocumentManagementService client)
{
_client = client;
}
This should help you out.