i am using "visual studio express for windows 8" and using Combo Box control as
<ComboBox Name="Categories" >
<x:String>apple</x:String>
<x:String>ball</x:String>
<x:String>cat</x:String>
<x:String>dog</x:String>
</ComboBox>
i want to show placeholder text in it to show some text until user hasn't selected any item from it. But when i use property PlaceholderText as described in microsoft reference to show text but when i use it the sdk shows this error
The member "PlaceholderText" is not recognized or is not accessible.
or is there any other method so that i can show some default text in Combobox.
Thanks.
This is for Windows 8.1 preview and not Windows 8 development. You will need to install the preview at this time before you can use and develop with this combobox. Looking at the docs for placeholder it states:
Minimum supported client Windows 8.1 Preview
Edit
To do this manually simply preload the combobox by hand. Here is an example, let us start with the ViewModel where the constructor will load an initial value into the combobox named "Loading"
public class MainVM : INotifyPropertyChanged
{
private List<string> _dataList;
public List<string> ComboData
{
get { return _dataList; }
set
{
if (_dataList != value)
{
_dataList = value;
OnPropertyChanged();
}
}
}
public MainVM()
{
ComboData = new List<string> {"Loading..."};
}
#region INotify Property Changed Implementation
/// <summary>
/// Event raised when a property changes.
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Raises the PropertyChanged event.
/// </summary>
/// <param name="propertyName">The name of the property that has changed.</param>
public void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
Now on the main page xaml bind to ComboData, but we need to be wary of the first situation where a list of one items will have loading, and we want to make that the selected item.
<ComboBox ItemsSource="{Binding ComboData}" Height="30" Width="300" Loaded="OnLoaded" />
Ok, in the code behind of the page we will set our datacontext to be the ViewModel we setup before, but also have an OnLoaded method which checks for the 1 item loading situation. In the below example we simulate a 3 second delay of loading the rest of the data.
public sealed partial class MainPage : Page
{
public MainVM ViewModel { get; set; }
public MainPage()
{
this.InitializeComponent();
DataContext = ViewModel = new MainVM();
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
var cBox = sender as ComboBox;
if (cBox != null)
{
if ((cBox.Items != null) && (cBox.Items.Count == 1))
{
cBox.SelectedIndex = 0;
// Debug code to simulate a change
Task.Run(() =>
{
// Sleep 3 seconds
new System.Threading.ManualResetEvent(false).WaitOne(3000);
Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{ ViewModel.ComboData = new List<string> {"Alpha", "Gamma", "Omega"}; });
});
}
}
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
}
}
Related
I have a background-thread which updates a Integer-value once per second. How can I map this Integer to a Text-Field of my XAML form that the Form always shows the current value and updates automatically if the Integer changes?
You can use a ViewModel with a binding.
With OnPropertyChanged() it will automatically changed and displayed in your UI.
here is an example to give you an idea
use in your xaml:
<TextBox x:Name="MyTextBox" Text="{Binding Name}".../>
in your code behind:
...
var vm = new ViewModel("Nr.7");
this.BindingContext = vm;
foreach(var x in Whatever)
{
vm.Name = x;
}
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace MyAppNamespace
{
// This class implements INotifyPropertyChanged
// to support one-way and two-way bindings
// (such that the UI element updates when the source
// has been changed dynamically)
public class ViewModel : INotifyPropertyChanged
{
private string name;
// Declare the event
public event PropertyChangedEventHandler PropertyChanged;
public ViewModel()
{
}
public ViewModel(string value)
{
this.name = value;
}
public string Name
{
get { return name; }
set
{
name = value;
// Call OnPropertyChanged whenever the property is updated
OnPropertyChanged();
}
}
// Create the OnPropertyChanged method to raise the event
// The calling member's name will be used as the parameter.
protected void OnPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
}
I am creating a custom control in Xamarin.Forms which is inherited from TemplatedView and using the application in all three platforms. For testing purposes, I need to set Automation ID for all native controls.
Usually, by using AutomationPeer we can set Automation ID to native UWP control from the UWP renderer project. But, in my custom control, I get this. Control is null always.
So, I can’t set Automation ID in UWP renderer class as Forms TemplatedView is a FrameworkElement in UWP.
My query is,
How to get a native element (this.Control) in UWP renderer project for Xamarin.Forms TemplatedView.
How to set Automation Id to native UWP control if this.Control is null.
The code snippet is provided below:
class FormsCustomLayout : TemplatedView
{
public static readonly BindableProperty InputViewProperty =
BindableProperty.Create(nameof(InputView), typeof(View), typeof(FormsCustomLayout), null, BindingMode.Default, null, OnInputViewChanged);
private static void OnInputViewChanged(BindableObject bindable, object oldValue, object newValue)
{
(bindable as FormsCustomLayout).OnInputViewChanged(oldValue, newValue);
}
private void OnInputViewChanged(object oldValue, object newValue)
{
var oldView = (View)oldValue;
if (oldView != null)
{
if (this.contentGrid.Children.Contains(oldView))
{
oldView.SizeChanged -= OnInputViewSizeChanged;
oldView.BindingContext = null;
this.contentGrid.Children.Remove(oldView);
}
}
var newView = (View)newValue;
if (newView != null)
{
newView.SizeChanged += OnInputViewSizeChanged;
newView.VerticalOptions = LayoutOptions.CenterAndExpand;
newView.HeightRequest = 60;
this.contentGrid.Children.Add(newView);
}
}
private void OnInputViewSizeChanged(object sender, EventArgs e)
{
}
public View InputView
{
get { return (View)GetValue(InputViewProperty); }
set { SetValue(InputViewProperty, value); }
}
internal void UpdateText(object text)
{
this.Text = (string)text;
}
private readonly Grid contentGrid = new Grid();
public FormsCustomLayout()
{
this.ControlTemplate = new ControlTemplate(typeof(StackLayout));
((StackLayout)Children[0]).Children.Add(this.contentGrid);
if (InputView != null)
{
this.contentGrid.Children.Add(InputView);
}
}
internal string Text { get; private set; }
}
The custom renderer code snippet is provided below:
class FormsCustomLayoutRenderer : ViewRenderer<FormsCustomLayout, FrameworkElement>
{
/// <summary>
/// Method that is called when the automation id is set.
/// </summary>
/// <param name="id">The automation id.</param>
protected override void SetAutomationId(string id)
{
if (this.Control == null)
{
base.SetAutomationId(id);
}
else
{
this.SetAutomationPropertiesAutomationId(id);
this.Control.SetAutomationPropertiesAutomationId(id);
}
}
/// <summary>
/// Provide automation peer for the control
/// </summary>
/// <returns>The TextInputLayout view automation peer.</returns>
protected override AutomationPeer OnCreateAutomationPeer()
{
if (this.Control == null)
{
return new FormsCustomLayoutAutomationPeer(this);
}
return new FormsCustomLayoutAutomationPeer(this.Control);
}
protected override void OnElementChanged(ElementChangedEventArgs<FormsCustomLayout> e)
{
base.OnElementChanged(e);
var element = e.NewElement;
}
}
internal class FormsCustomLayoutAutomationPeer : FrameworkElementAutomationPeer
{
/// <summary>
/// Initializes a new instance of the <see cref="FormsCustomLayoutRenderer"/> class.
/// </summary>
/// <param name="owner">FormsCustomLayout View control</param>
public FormsCustomLayoutAutomationPeer(FrameworkElement owner) : base(owner)
{
}
/// <summary>
/// Describe the control type
/// </summary>
/// <returns>The control type.</returns>
protected override AutomationControlType GetAutomationControlTypeCore()
{
return AutomationControlType.Custom;
}
/// <summary>
/// Describe the class name.
/// </summary>
/// <returns>The Class Name.</returns>
protected override string GetClassNameCore()
{
return "FormsCustomLayout";
}
}
Demo sample attached here: FormsCustomControl
Please share your idea or solution to set Automation ID.
Regards,
Bharathiraja.
I am very new to the MVVM style. I have been able to accomplish everything in the past by writing extensive code in the code behind the XAML. However, I am trying to convert everything into MVVM.
Issue:
I am unable to bind a datagrid to my ObservableCollection. When I debug and walk through my code, the ObservableCollection list is being properly set, meaning, i can view the data within the variables and it shows the data i am adding; however, my data grid does not display the data. Upon reading I found that if I used an ObservableCollection, I didn't need an INotifyPropertyChanged; but because that didn't work, i do have one on there now. Sadly, that still isn't populating my datagrid.
Any help you can offer is appreciated.
In the end, I am going to have a list of type Members, and i need the data grid to populate the data about each member. The data comes from the Members class.
Xaml:
<DataGrid ItemsSource="{Binding Source=PHList}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Member Name" Binding="{Binding Member_Name}"/>
<DataGridTextColumn Header="Medicaid ID" Binding="{Binding Medicaid_ID}"/>
</DataGrid.Columns>
</DataGrid>
Priority Health Model:
public PriorityHealthMember(string name, string id)
{
Member_Name = name;
Medicaid_ID = id;
}
private string _Member_Name;
public String Member_Name
{
get
{
return _Member_Name;
}
set
{
_Member_Name = value;
OnPropertyChanged("Member_Name");
}
}
private string _Medicaid_ID;
public String Medicaid_ID
{
get
{
return _Medicaid_ID;
}
set
{
_Medicaid_ID = value;
OnPropertyChanged("Medicaid_ID");
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
Onboarding ViewModel
private ObservableCollection<PriorityHealthMember> _PHList;
public ObservableCollection<PriorityHealthMember> PhList
{
get
{
return _PHList;
}
set
{
_PHList = value;
OnPropertyChanged("PhList");
}
}
public OnboardingQueueViewModel()
{
PhList = GetOnboardingQueueList();
}
private ObservableCollection<PriorityHealthMember> GetOnboardingQueueList()
{
ObservableCollection<PriorityHealthMember> list = new ObservableCollection<PriorityHealthMember>();
list.Add(new PriorityHealthMember("Andrews, Nicholas", "M123456"));//Testing for now. Will add the Business Logic after binding works.
return list;
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
I found my issue. In my xaml i had "PHList" however, my property was "PhList"
I've been trying my hand at creating a simple user control with dependencyproperty and binding it, but it doesn't seem to work, not sure why. I'll just dive straight into code, please ignore the fact that the control doesn't make sense, it's just for illustrative purposes (written in WP8 if that matters).
My simple user control, it's basically a line with a property to turn it off or on.
<Grid x:Name="LayoutRoot" Background="Transparent">
<Line Height="105" Width="105" X2="100" Y2="100" Visibility="{Binding LineVisible}" Stroke="#FFFC1515" StrokeThickness="5"/>
</Grid>
public partial class SimpleUserControl : UserControl
{
public SimpleUserControl()
{
InitializeComponent();
DataContext = this;
}
public static readonly DependencyProperty LineVisibleProperty = DependencyProperty.Register("LineVisible", typeof(bool), typeof(SimpleUserControl), new PropertyMetadata(new PropertyChangedCallback(OnLineVisibleChanged)));
public bool LineVisible
{
get { return (bool)GetValue(LineVisibleProperty); }
set { SetValue(LineVisibleProperty, value); }
}
private static void OnLineVisibleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
bool newvalue = (bool)e.NewValue;
Visibility vis = newvalue ? Visibility.Visible : Visibility.Collapsed;
(d as SimpleUserControl).Visibility = vis;
}
}
The test app
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<uc:SimpleUserControl LineVisible="{Binding class1.Vis}"/>
</Grid>
public partial class MainPage : PhoneApplicationPage
{
public Class1 class1 { get; set; }
public MainPage()
{
InitializeComponent();
DataContext = this;
}
private void PhoneApplicationPage_Loaded_1(object sender, RoutedEventArgs e)
{
class1 = new Class1() { Vis = false };
}
}
The class1 that it's bound to
public class Class1 : INotifyPropertyChanged
{
private bool _vis;
public bool Vis
{
get { return _vis; }
set
{
_vis = value;
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("Vis"));
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
It doesn't seem to work, however, if it is set explicitly like below it works.
<uc:SimpleUserControl LineVisible="False"/>
I'm sure it's something simple, but I'm not seeing it.
Thanks for any help.
The problem was I was setting the DataContext = this in the UserControl and when binding to Vis in the testapp, it would override and search for Vis in the UserControl (which of course does not exist there). I did see binding errors in the debug output window which confirms this. The solution was to set the LayoutRoot of the UserControl to this as was mentioned in the link I posted earlier.
The Visibility property of WPF controls does not use bool values, it requires the Visibility enum. Thus you have two options:
Change LineVisibiltyProperty to Visibility instead of bool.
Use a converter to bind to bool and convert to Visibility.
I would suggest using the second option as this in my opinion is the better solution.
This might be helpful.
I created a WP Class Library BusinessLogic project which is composed by these three class
1) Bottle Class
namespace BusinessLogic
{
public class Bottle : INotifyPropertyChanged
{
// Due to INotifyPropertyChanged interface
public event PropertyChangedEventHandler PropertyChanged;
// Proprietà Title
private string title;
public string Title
{
set
{
if (title != value)
{
title = value;
OnPropertyChanged("Title");
}
}
get
{
return title;
}
}
// Proprietà PhotoFileName
private string photoFileName;
public string PhotoFileName
{
set
{
if (photoFileName != value)
{
photoFileName = value;
OnPropertyChanged("PhotoFileName");
}
}
get
{
return photoFileName;
}
}
protected virtual void OnPropertyChanged(string propChanged)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propChanged));
}
}
}
2) Bottles Class
namespace BusinessLogic
{
public class Bottles : INotifyPropertyChanged
{
// Due to INotifyPropertyChanged interface
public event PropertyChangedEventHandler PropertyChanged;
// Proprietà MainTitle
private string mainTitle;
public string MainTitle
{
set
{
if (mainTitle != value)
{
mainTitle = value;
OnPropertyChanged("MainTitle");
}
}
get
{
return mainTitle;
}
}
// Proprietà bottles
private ObservableCollection<Bottle> bottleSet = new ObservableCollection<Bottle>();
public ObservableCollection<Bottle> BottleSet
{
set
{
if (bottleSet != value)
{
bottleSet = value;
OnPropertyChanged("BottleSet");
}
}
get { return bottleSet; }
}
protected virtual void OnPropertyChanged(string propChanged)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propChanged));
}
}
}
3) BottlesPresenter Class
namespace BusinessLogic
{
public class BottlesPresenter : INotifyPropertyChanged
{
// Due to INotifyPropertyChanged interface
public event PropertyChangedEventHandler PropertyChanged;
// Proprietà BottleMatrix
private Bottles bottlesMatrix;
public Bottles BottlesMatrix
{
protected set
{
if (bottlesMatrix != value)
{
bottlesMatrix = value;
OnPropertyChanged("BottlesMatrix");
}
}
get { return bottlesMatrix; }
}
public BottlesPresenter()
{
XmlSerializer xml = new XmlSerializer(typeof(Bottles));
using (StreamReader fileReader = new StreamReader(#"C:\Stuff\WindowsPhone\AppLearningHowTo2\AppLearningHowTo2\DAL\DB.xml"))
{
BottlesMatrix = (Bottles)xml.Deserialize(fileReader);
}
}
protected virtual void OnPropertyChanged(string propChanged)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propChanged));
}
}
}
The BottlePresenter constructor should deserialize from an xml file located into the file system. It contains the following tags
<?xml version="1.0"?>
<Bottles xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<MainTitle>MainTitle</MainTitle>
<Bottleset>
<Bottle>
<Title>Title1</Title>
<PhotoFileName>PhotoFileName1</PhotoFileName>
</Bottle>
<Bottle>
<Title>Title2</Title>
<PhotoFileName>PhotoFileName2</PhotoFileName>
</Bottle>
</Bottleset>
</Bottles>
Then I created a WP Application and I made a reference to the BusinessLogic.dll project library.
In the MainPage.xaml file I put the XML namespace declaration
xmlns:businesslogic="clr-namespace:BusinessLogic;assembly=BusinessLogic"
I then instantiated the BottlesPresenter class in the MainPage.xaml Resources collection
<phone:PhoneApplicationPage.Resources>
<businesslogic:BottlesPresenter x:Key="bottlesPresenter" />
</phone:PhoneApplicationPage.Resources>
And finally put a TextBlock in the content area with a binding to that resource:
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<TextBlock HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="{Binding Source={StaticResource bottlesPresenter},
Path=Bottles.MainTitle}" />
Unfortunately I launch the debugger, the emulator switch on, reach the splashscreen and doesn't go on.
In a nutshell: I can't reach to create an instance of the BottlesPresenter class.
I banged my head against the wall for weeks without finding a solution.
Please could someone give me a hand?
Thank you very much
Antonio
Emulator behaves like that when WP7 cannot construct Application object. From question, I see only 1 reference from Application to your code. It's BottlePresenter in Resources.
XamlLoader tries to create instance of this type.
See what's inside your BottlePresenter constructur:
public BottlesPresenter()
{
XmlSerializer xml = new XmlSerializer(typeof(Bottles));
using (StreamReader fileReader = new StreamReader(
#"C:\Stuff\WindowsPhone\AppLearningHowTo2\AppLearningHowTo2\DAL\DB.xml"))
{
BottlesMatrix = (Bottles)xml.Deserialize(fileReader);
}
}
First line is OK.
Second line is OK.
Third line causes exception, because path "C:\Stuff\WindowsPhone\AppLearningHowTo2\AppLearningHowTo2\DAL\DB.xml" is not acceptable on Windows Phone.
All files you can access is Content of your XAP, Resources in your assembly, and files in Isolated Storage.
Following articles might help you All about WP7 Isolated Storage - Read and Save Text files