I want to bind to a resource (DynamicResource) and access properties on that resource, but is there a way to do that?
(I want to visualize the default values from constructor in the xaml editor in visual studio. Those cannot be seen when referencing an object through DataContext nor through a property added on my Window class...)
Not working xaml: (works in composer but not at runtime...)
<Window ... >
<Window.Resources>
<local:MyClass x:Key="myResource" />
</Window.Resources>
<StackPanel>
<Button Content="{Binding Source={DynamicResource myResource} Path=Property1}" />
<Button Content="{Binding Source={DynamicResource myResource} Path=Property2}" />
</StackPanel>
</Window>
with the class (which probably need to implement INotifyPropertyChanged):
public class MyClass
{
public MyClass()
{
this.Property1 = "Ok";
this.Property2 = "Cancel";
}
public string Property1 { get; set; }
public string Property2 { get; set; }
}
That's because the DynamicResource markup extension can only be used on a dependency property, because it will need to update it if the resource changes. And Binding.Source is not a dependency property...
As a workaround, you could set the DataContext of the button with the DynamicResource :
<Button DataContext="{DynamicResource myResource}" Content="{Binding Path=Property1}" />
<Button DataContext="{DynamicResource myResource}" Content="{Binding Path=Property2}" />
Abusing the DataContext of an unrelated object seems to be the easiest workaround.
In case you still need the DataContext of your control (MVVM anyone?), you can also create an invisible helper FrameworkElement elsewhere:
<FrameworkElement Visibility="Collapsed" x:Name="ControlBrushGetter" DataContext="
{DynamicResource {x:Static SystemColors.ControlBrushKey}}" />
and later refer to it by using the name in the binding:
<SolidColorBrush Opacity="0.8"
Color="{Binding ElementName=ControlBrushGetter, Path=DataContext.Color}" />
Your designer will quite likely complain about not being able to resolve "Color" in the context of "object", but it will work fine at runtime.
Related
Here is the situation that I have:
<Stack IsVisible="{Binding IsGood}" >
<Label Text="Is Good or Okay" />
</Stack>
<Stack IsVisible="{Binding IsOkay}" >
<Label Text="Is Good or Okay" />
</Stack>
What I would like to do is to somehow code it like this:
<Stack IsVisible="{Binding IsGood, IsOkay, Converter={StaticResource ORConverter} }" >
<Label Text="Is Good or Okay" />
</Stack>
You can't make a converter do that. A converter only takes one value. Instead, why not just use a property in the ViewModel which reflects this instead?
public bool AorB => A || B;
private bool _a;
public bool A
{
get => _a;
set
{
_a = value;
RaisePropertyChanged();
RaisePropertyChanged(nameof(AorB));
}
}
private bool _b;
public bool B
{
get => _b;
set
{
_b = value;
RaisePropertyChanged();
RaisePropertyChanged(nameof(AorB));
}
}
Now, if you are using MvvmCross, you could use the Value Combiners it provides. However, it will only work for MvvmCross's binding descriptions, which would look like:
If(Or(A, B), 'true', 'false')
That would need you to depend on MvvmCross though and switch to its bindings for these kind of operations.
I am trying to push the text from my Shell.SearchHandler to a command.
I have built this with SearchBar , but i need this to work in the Shell.SearchHandler
<Shell.SearchHandler >
<SearchHandler x:Name="searchBar"
Placeholder="Search..."
Command="{Binding PerformSearch}"
CommandParameter="{Binding Text, Source={x:Reference searchBar}}" TextColor="Black" BackgroundColor="LightGray" />
</Shell.SearchHandler>
And in my View model
public ICommand PerformSearch => new Command<string>((string query) =>
{
//do work
});
The command does execute but the query param is always null.
How can I get the text that was entered into the searchandler to be posted to the binding command?
CommandParameter="{Binding Text, Source={x:Reference searchBar}}"
After having a look at SearchHandler reference document as follow :
Query, of type string, the user entered text in the search box.
The reason is that SearchHandler not contains Text property .You should replace it with Query , then it can work .
<Shell.SearchHandler >
<SearchHandler x:Name="searchBar"
Placeholder="Search..."
Command="{Binding PerformSearch}"
CommandParameter="{Binding Query, Source={x:Reference searchBar}}"
TextColor="Black"
BackgroundColor="LightGray" />
</Shell.SearchHandler>
Note : Also can Custom a SearchHandler to monitor Query changed if needed .
Creare a MySearchHandler :
public class MySearchHandler : SearchHandler
{
protected override void OnQueryChanged(string oldValue, string newValue)
{
base.OnQueryChanged(oldValue, newValue);
if (string.IsNullOrWhiteSpace(newValue))
{
ItemsSource = null;
}
else
{
Console.WriteLine("search string " + newValue);
// here you can add code to deal with the viewmodel
//ItemsSource = MonkeyData.Monkeys
.Where(monkey => monkey.Name.ToLower().Contains(newValue.ToLower()))
.ToList<Animal>();
}
}
}
In Xaml :
<ContentPage ...
xmlns:controls="clr-namespace:Xaminals.Controls">
<Shell.SearchHandler>
<controls:MonkeySearchHandler Placeholder="Enter search term"
ShowsResults="true"
DisplayMemberName="Name" />
</Shell.SearchHandler>
...
</ContentPage>
Here is the official sample for reference , this need some time to research it.
I have been trying to use the x:name of the entry field to store the username of a twitter user and then using it for accessing the feeds. But I'm facing this error: cannot convert from 'Xamarin.Forms.Entry' to 'Tweetinvi.Models.IUserIdentifier'. What to do?
XAML File
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="App7.Views.AnalysisPage">
<ContentPage.Content>
<StackLayout VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand">
<Entry x:Name="twitteruser_entry" Placeholder="#Username"></Entry>
</StackLayout>
</ContentPage.Content> </ContentPage>
XAML.CS File
using System.Threading.Tasks;
using Xamarin.Forms;
using Tweetinvi;
using Xamarin.Forms.Xaml;
using Tweetinvi.Models.Webhooks;
namespace App7.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class AnalysisPage : ContentPage
{
public AnalysisPage ()
{
var user_identifier = twitteruser_entry; //this is where i'm getting the error.
var User = (dynamic)null;
var authenticatedUser = User.GetAuthenticatedUser();
var tweets = Timeline.GetUserTimeline(user_identifier, 10);
}
}
}
This is failing because it is trying all of the overloads and only returns the error on the last one.
Given the name of the field I am going to assume that the user is going to enter their username into the field. In this case you are probably wanting this overload
public static IEnumerable<ITweet> GetUserTimeline(string userScreenName, IUserTimelineParameters userTimelineParameters)
If this is the case, you need to get the text from the entry and pass it to that method.
var tweets = Timeline.GetUserTimeline(user_identifier.Text, 10);
I've been trying to reproduce the simplest validation logic ever possible with template 10 validation, but I Just dont get it.
I have created my Model like the wiki at the example at github:
public class User : ValidatableModelBase
{
//public User()
//{
// FirstName = string.Empty;
// LastName = string.Empty;
// Validator = i =>
// {
// var u = i as User;
// if (string.IsNullOrEmpty(u.FirstName))
// u.Properties[nameof(u.FirstName)].Errors.Add("The first name is required");
// else if (u.FirstName.Length <= 3)
// u.Properties[nameof(u.FirstName)].Errors.Add("First Name must be greater than 3 chars.");
// if (string.IsNullOrEmpty(u.LastName))
// u.Properties[nameof(u.LastName)].Errors.Add("The last name is required");
// else if (u.LastName.Length <= 3)
// u.Properties[nameof(u.LastName)].Errors.Add("Last Name must be greater than 3 chars.");
// };
//}
public int Id { get; set; }
public string FirstName
{
get
{
return Read<string>();
}
set
{
Write(value);
}
}
public string LastName
{
get
{
return Read<string>();
}
set
{
Write(value);
}
}
public override string ToString() => $"{FirstName} {LastName}";
}
as you can see I've even created a constructor to initialize my Object, I commented out because I wanted to initialize the values at my ViewModel Constructor.
Then my view model is this:
public class MainPageViewModel : ViewModelBase
{
public MainPageViewModel()
{
User = new User
{
FirstName = string.Empty,
LastName = string.Empty,
Validator = i =>
{
var u = i as User;
if (string.IsNullOrEmpty(u.FirstName))
u.Properties[nameof(u.FirstName)].Errors.Add("The first name is required");
else if (u.FirstName.Length <= 3)
u.Properties[nameof(u.FirstName)].Errors.Add("First Name must be greater than 3 chars.");
if (string.IsNullOrEmpty(u.LastName))
u.Properties[nameof(u.LastName)].Errors.Add("The last name is required");
else if (u.LastName.Length <= 3)
u.Properties[nameof(u.LastName)].Errors.Add("Last Name must be greater than 3 chars.");
},
};
}
private User _User;
public User User
{
get { return _User; }
set { _User = value; }
}
public override async Task OnNavigatedToAsync(object parameter, NavigationMode mode, IDictionary<string, object> suspensionState)
{
User.Validate();
await Task.CompletedTask;
}
public override async Task OnNavigatingFromAsync(NavigatingEventArgs args)
{
args.Cancel = false;
await Task.CompletedTask;
}
public void GotoSettings() =>
NavigationService.Navigate(typeof(Views.SettingsPage), 0);
public void GotoPrivacy() =>
NavigationService.Navigate(typeof(Views.SettingsPage), 1);
public void GotoAbout() =>
NavigationService.Navigate(typeof(Views.SettingsPage), 2);
}
Now at my view all I have is this:
<Page x:Class="ValidationSample.Views.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Behaviors="using:Template10.Behaviors"
xmlns:Core="using:Microsoft.Xaml.Interactions.Core"
xmlns:Interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:controls="using:Template10.Controls"
xmlns:validate="using:Template10.Controls.Validation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:ValidationSample.Views"
xmlns:m="using:ValidationSample.Models"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:ValidationSample.ViewModels" mc:Ignorable="d">
<Page.DataContext>
<vm:MainPageViewModel x:Name="ViewModel" />
</Page.DataContext>
<RelativePanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="AdaptiveVisualStateGroup">
<VisualState x:Name="VisualStateNarrow">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="{StaticResource NarrowMinWidth}" />
</VisualState.StateTriggers>
<VisualState.Setters>
<!-- TODO: change properties for narrow view -->
<!--<Setter Target="stateTextBox.Text" Value="Narrow Visual State" />-->
</VisualState.Setters>
</VisualState>
<VisualState x:Name="VisualStateNormal">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="{StaticResource NormalMinWidth}" />
</VisualState.StateTriggers>
<VisualState.Setters>
<!-- TODO: change properties for normal view -->
<!--<Setter Target="stateTextBox.Text" Value="Normal Visual State" />-->
</VisualState.Setters>
</VisualState>
<VisualState x:Name="VisualStateWide">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="{StaticResource WideMinWidth}" />
</VisualState.StateTriggers>
<VisualState.Setters>
<!-- TODO: change properties for wide view -->
<!--<Setter Target="stateTextBox.Text" Value="Wide Visual State" />-->
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<controls:PageHeader x:Name="pageHeader" RelativePanel.AlignLeftWithPanel="True"
RelativePanel.AlignRightWithPanel="True"
RelativePanel.AlignTopWithPanel="True" Text="Main Page">
<!-- secondary commands -->
<controls:PageHeader.SecondaryCommands>
<AppBarButton Click="{x:Bind ViewModel.GotoSettings}" Label="Settings" />
<AppBarButton Click="{x:Bind ViewModel.GotoPrivacy}" Label="Privacy" />
<AppBarButton Click="{x:Bind ViewModel.GotoAbout}" Label="About" />
</controls:PageHeader.SecondaryCommands>
</controls:PageHeader>
<validate:ControlWrapper PropertyName="FirstName"
RelativePanel.AlignLeftWithPanel="True"
RelativePanel.Below="pageHeader">
<TextBox Width="300"
Margin="12,0,0,0"
Header="First Name"
Text="{Binding FirstName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</validate:ControlWrapper>
</RelativePanel>
As fas as I know I have the model with the ValidatableModelBase logic Applied, I do have the Validate:wrapper applied to the view, I've set the validator at the VM ctor or I could set it at model ctor.
My problem is where do i make the Calling logic???
Because I havent been able to trigger the UpdateSourceTrigger of my FirstName field.
What am i doing wrong??
To be more honest I dont know where to place the Validate method, because at the sample at github the validate method is call everytime you open the modal dialog window, but that is when you are navigating to that window and its field everytime they changed they are being validated, but in my case nothing happens, why?? Hopefully someone can help me out, since I'm new at template 10 and also at UWP.
Damn, I was so damn tired but my mistake was so god damn simple I forgot to set the DataContext at the Parent Panel, In this case I should had add DataContext ={Binding Model}
this at XAML within the relative panel or any other Panel.
I felt so noob to have made this question.
I've got a problem trying to set a custom label on teh fly with a ribbon using Excel-DNA.
If I don't included the annotation "getLabel='GetLabel'" then the plugin loads fine. ie the ribbon tab is shown with 2 buttons andthe button callbacks work fine.
If I do inclue the property "getLabel='GetLabel'" then the plugin doesn't even load, ie onLoad isn't called and the ribbon tab doesn't show up in excel.
Can anyone see what I'm doing wrong here. I don't see any errors when running in the debugger.
Here is my DNA file. I've tried to base it off one of the samples so it's easier to follow.
<DnaLibrary Name="Emsx Addin" RuntimeVersion="v2.0">
<ExternalLibrary Path="EmsxExcelTech1.dll" />
<Reference AssemblyPath="System.Windows.Forms.dll" />
<!-- Some images that can be used in the Ribbon ui -->
<Image Name="M" Path="M.png" Pack="true" />
<CustomUI>
<customUI xmlns='http://schemas.microsoft.com/office/2009/07/customui' loadImage='LoadImage' onLoad='OnLoad'>
<ribbon>
<tabs>
<tab id='CustomTab' label='K2 Emsx' insertAfterMso='View'>
<group id='SampleGroup' label='Global Sheet Status'>
<button id='LoginCmd' label='Logon' image='M' onAction='OnLogonPressed' getLabel='GetLabel' />
<button id='BetaCmd' label='Use Beta Route' image='M' size='normal' onAction='RunTagMacro' tag='OnUseBetaRoutes' />
</group >
</tab>
</tabs>
</ribbon>
</customUI>
</CustomUI>
</DnaLibrary>
Here is my Ribbon derived C# file.
[ComVisible(true)]
public class EmsxRibbon : ExcelRibbon
{
private IRibbonUI ribbon = null;
public void OnLogonPressed(IRibbonControl control)
{
EmsxIntegration.Instance.Login();
MessageBox.Show("Hello from control " + control.Id);
if (ribbon != null)
{
ribbon.InvalidateControl(control.Id);
}
}
string GetLabel(IRibbonControl control)
{
if (control.Tag == "Logon")
{
return "Logon";
}
else
{
return "Logoff";
}
}
public static void OnUseBetaRoutes()
{
MessageBox.Show("Hello from 'ShowHelloMessage'.");
}
public void OnLoad(IRibbonUI ribbon)
{
this.ribbon = ribbon;
}
}
When you use the getLabel event, you should not use label property, so change
<button id='LoginCmd' label='Logon' image='M' onAction='OnLogonPressed' getLabel='GetLabel' />
to
<button id='LoginCmd' image='M' onAction='OnLogonPressed' getLabel='GetLabel' />
Hope this helps.