how to bind the DataGridTextColumn visibility - binding

I am trying to bind the visibility of datagrid as GreatTall1 suggested in his post from this thread
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
namespace XYZ.Controls
{
public class ExtendedDataGridTextColumn : DataGridTextColumn
{
private readonly Notifier _e;
private Binding _visibilityBinding;
public Binding VisibilityBinding
{
get { return _visibilityBinding; }
set
{
_visibilityBinding = value;
_e.SetBinding(Notifier.MyVisibilityProperty, _visibilityBinding);
}
}
public ExtendedDataGridTextColumn()
{
_e = new Notifier();
_e.PropertyChanged += ToggleVisibility;
}
private void ToggleVisibility(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Visibility")
this.Visibility = _e.MyVisibility;
}
//Notifier class is just used to pass the property changed event back to the column container Dependency Object, leaving it as a private inner class for now
private class Notifier : FrameworkElement, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public Visibility MyVisibility
{
get { return (Visibility)GetValue(MyVisibilityProperty); }
private set { SetValue(MyVisibilityProperty, value); }
}
public static readonly DependencyProperty MyVisibilityProperty = DependencyProperty.Register("MyVisibility", typeof(Visibility), typeof(Notifier), new PropertyMetadata(MyVisibilityChanged));
private static void MyVisibilityChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var n = d as Notifier;
if (n != null)
{
// n.MyVisibility = (Visibility) e.NewValue;
n.PropertyChanged(n, new PropertyChangedEventArgs("Visibility"));
}
}
}
}
I have added the class to my solution, and try to bind the DataGridTextColumn visibility to my IdVisibility property
<sdk:DataGrid x:Name="dgResult" Grid.Row="0" VerticalAlignment="Stretch" SelectionMode="Single" HorizontalAlignment="Stretch" AutoGenerateColumns="False" ItemsSource="{Binding IdSearchList}" IsReadOnly="True" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" Margin="10" Visibility="{Binding IsResultVisible}">
<extDg:ExtendedDataGridTextColumn Binding="{Binding Id}" VisibilityBinding="{Binding IdVisibility}" Header="Asset ID" Width="50"/>
private Visibility idVisibility = Visibility.Collapsed;
public Visibility IdVisibility
{
get { return idVisibility; }
set { idVisibility = value; NotifyPropertyChanged("IdVisibility"); }
}
The column is always being displayed regardless of the value of IdVisibility.
Please, could someone point out what i am doing wrong? This is a SL4 app
Thanks

I Think You Should Use Visiblity Converter Also You Can Bind With Designer with This Converter
Public NotInheritable Class VisibilityConverter
Implements IValueConverter
Public Function Convert(ByVal value As Object, ByVal targetType As System.Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.Convert
If Not targetType Is GetType(Visibility) Then
Throw New ArgumentOutOfRangeException("targetType", "VisibilityConverter can only convert to Visibility")
End If
Dim _visibility As Visibility = Visibility.Visible
If value Is Nothing Then
_visibility = Visibility.Collapsed
End If
If TypeOf (value) Is Boolean Then
_visibility = IIf(value, Visibility.Visible, Visibility.Collapsed)
End If
If TypeOf (value) Is String Then
_visibility = IIf(String.IsNullOrEmpty(value), Visibility.Collapsed, Visibility.Visible)
End If
Return _visibility
End Function
Public Function ConvertBack(ByVal value As Object, ByVal targetType As System.Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.ConvertBack
Throw New ArgumentOutOfRangeException("targetType", "VisibilityConverter can only convert to Boolean")
End Function
End Class

Related

How to modify binded value in MVVM Cross

I have a model from my json in a Xamarin MVVM app(ios). I want to add the "%" after the value? in the list "coinmarketcaplist" contains the value 24h_change, this is the value I want to add a % to, it's a string. I know that I should use a getter for it, but I don't know how since I'm fairly new to this. below is my ViewModel code:
public class CMCTableViewModel : MvxViewModel
{
protected readonly ICoinMarketCapService _coinMarketCapService;
public CMCTableViewModel(ICoinMarketCapService coinMarketCapService)
{
_coinMarketCapService = coinMarketCapService;
LoadData();
}
private List<CoinMarketCapModel> _coinMarketCapModelList;
public List<CoinMarketCapModel> CoinMarketCapModelList
{
get
{
return _coinMarketCapModelList;
}
set
{
_coinMarketCapModelList = value;
RaisePropertyChanged(() => CoinMarketCapModelList);
}
}
public async void LoadData()
{
CoinMarketCapModelList = await _coinMarketCapService.GetCoins();
}
}
TableCell:
internal static readonly NSString Identifier = new NSString("CMCTableCell");
public override void LayoutSubviews()
{
base.LayoutSubviews();
MvxFluentBindingDescriptionSet<CMCTableCell, CoinMarketCapModel> set = new MvxFluentBindingDescriptionSet<CMCTableCell, CoinMarketCapModel>(this);
set.Bind(lblName).To(res => res.Name);
set.Bind(lblPrice).To(res => res.percent_change_24h);
set.Bind(imgCoin)
.For(img => img.Image)
.To(res => res.image)
.WithConversion<StringToImageConverter>();
set.Apply();
}
}
edit: added cellview
Use a converter in your binding:
1) Define converter:
public class StringFormatValueConverter : MvxValueConverter
{
public override object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null)
return null;
if (parameter == null)
return value;
return string.Format(parameter.ToString(), value);
}
}
2) Use it in your binding:
set.Bind(lblPrice).To(res => res.percent_change_24h).WithConversion<StringFormatValueConverter>("{0} %");
You can use this converter when you want to modify the input string by adding something around it, for example unit or currency

Conection MVVM Light with SelectionChanged

I'm creating app in UWP and i have question.
Can I somehow connection MVVM Light with SelectionChanged event (e.g. ListView) or with other event?
I would like that when I will click on some Item in ListView then I call SelectionChanged.
How do I do?
You can write the Method in ViewModel ,and use the x:bind to connection ViewModel.
The MVVMLight's method is use in WPF that cant bind the event in Method.
UWP can use x:bind to bind the UI event to ViewModel.
The sample:
XAML:
<ListView SelectionChanged = "{x:bind view.SelectionChanged }"/>
XAML.cs:
private ViewModel View{set;get;}
ViewModel:
public void SelectionChanged()
{
}
You can use ItemClick event that will run when you click the ListViewItem .
Inside your viewmodel something *.cs
public class RelayCommand : ICommand
{
private Predicate<object> _canExecute;
private Action<object> _execute;
public RelayCommand(Predicate<object> canExecute, Action<object> execute)
{
this._canExecute = canExecute;
this._execute = execute;
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public bool CanExecute(object parameter)
{
return _canExecute(parameter);
}
public void Execute(object parameter)
{
_execute(parameter);
}
}
public class MyViewModel
{
private ICommand _doSelectionChangedCommand;
public ICommand DoSelectionChangedCommand
{
get
{
if (_doSelectionChangedCommand == null)
{
_doSelectionChangedCommand = new RelayCommand(
p => this.CanSelectionChanged,
p => this.DoSomeImportantMethod());
}
return _doSomething;
}
}
}
In your viewSomemthing.xaml
--For namespace
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
--Then go down to your control, we'll use Combobox as an example
<ComboBox ... />
<i:Interaction.Triggers>
<EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding DoSelectionChangedCommand}"/>
</EventTrigger>
</i:Interaction.Triggers>
</ComboBox>

Autofac. How to get caller class Type?

Suppose we have two classes with same constructor Injectable dependency:
public class FirstClass
{
public FirstClass(ISomeDependency someDependency)
{ }
}
public class SecondClass
{
public SecondClass(ISomeDependency someDependency)
{ }
}
Now we have a registration for ISomeDependency:
builder.Register(x =>
{
string key = GetKeyFromCurrentHttpRequest();
// if "Caller" is "FirstClass" return new Dependency(key);
// else return new Dependency("defaultKey");
}).As<ISomeDependency>();
Note: This is a simplified use case. The real scenario is much more complicated.
1. How to get "Caller" type which tryies to resolve ISomeDependency?
2. Is there a better way design for such situations?
You can use delegate factories do achieve your goal. The only drawback is the FirstClass and SecondClass cannot use ISomeDependency as parameter.
You can try this code in a console application (just add Autofac dependency).
using System;
using Autofac;
namespace test
{
class MainClass
{
public static void Main(string[] args)
{
ContainerBuilder builder = new ContainerBuilder ();
builder.RegisterType<SomeDependency>().As<ISomeDependency>();
builder.RegisterType<FirstClass>();
builder.RegisterType<SecondClass>();
var container = builder.Build();
var dummy = container.Resolve<FirstClass>();
var dummy2 = container.Resolve<SecondClass>();
}
public interface ISomeDependency
{
}
public class SomeDependency : ISomeDependency
{
public delegate ISomeDependency Factory(string value);
private readonly string _value;
public SomeDependency(string value)
{
_value = value;
Console.WriteLine("Value = " + _value);
}
}
public class FirstClass
{
private ISomeDependency _dependency;
public FirstClass(SomeDependency.Factory factory)
{
_dependency = factory.Invoke("my value");
}
}
public class SecondClass
{
private ISomeDependency _dependency;
public SecondClass(SomeDependency.Factory factory)
{
_dependency = factory.Invoke("my value 2");
}
}
}
}

selectOneMenu with complex objects, is a converter necessary? [duplicate]

This question already has answers here:
Conversion Error setting value for 'null Converter' - Why do I need a Converter in JSF?
(2 answers)
Closed 7 years ago.
Is a Converter necessary for a <h:selectOneMenu> or <p:selectOneMenu> with arbitrary user-created classes as its values? I mean, is the following code supposed to work without a converter?
<p:selectOneMenu value="#{bean.language}">
<f:selectItems value="#{bean.allLanguages}" />
</p:selectOneMenu>
and
#Named(value = "bean")
#ConversationScoped
public class Bean {
private Language language; // appropriate getter and setter are present
public List<SelectItem> getAllLanguages() {
// populates a list of select items with Strings as item labels and Languages as item values
}
}
I have a similar code with an enum as the type (Language) and it works perfectly. But when I replace the type with a normal java class, I get a conversion error.
You need a converter here, as JSF will assume strings by default, that is the way you coded it. JSF has no idea how to convert your pseudo entities to strings and vice versa.
Some notes:
1 . Your getAsString method defines your identifier for your entities/POJOs, not what the JSF (or whatever) select gets as itemLabel.
2 . Your converter can dig into the DB for real entities using this infamous article:
http://balusc.blogspot.de/2011/09/communication-in-jsf-20.html#ConvertingAndValidatingGETRequestParameters
You can also use CDI annotations with that "pattern".
3 . Your value = "bean"is redundant and the CDI scope of choice is usually #ViewScoped. However, you have to keep in mind that CDI #Named + JSF #ViewScoped isn't working together without using Seam 3 or Apache MyFaces CODI.
You do not need a converter, if you use this little class that I wrote :-) It can back selectOne and selecteMany components. It requires that your class's toString() provides a one-to-one unique representation of your object. If you like, you could substitute a method name other than toString(), like toIDString()
To use ListBacker in your ManagedBean, use ListBacker<Type> wherever you would have used List<Type>
#ManagedBean
#RequestScoped
public class BackingBean {
private ListBacker<User> users; // +getter +setter
#PostConstruct
public void init() {
// fill it up from your DAO
users = new ListBacker<User>(userDAO.find());
}
// Here's the payoff! When you want to use the selected object,
// it is just available to you, with no extra database hits:
User thisOneIsSelected = users.getSelectedItemAsObject();
// or for multi-select components:
List<User> theseAreSelected = users.getSelectedItemsAsObjects();
}
In your xhtml file:
<p:selectOneMenu value="#{backingBean.users.selectedItem}">
<f:selectItems value="#{backingBean.users.contents}" var="item" itemValue="#{item.value}" itemLabel="#{item.label}" />
</p:selectOneMenu>
The ListBacker class:
public class ListBacker<T extends AbstractEntityBase> {
// Contains the String representation of an Entity's ID (a.k.a.
// primary key) and the associated Entity object
Map<String, T> contents = new LinkedHashMap<String, T>(); // LinkedHashMap defaults to insertion-order iteration.
// These hold values (IDs), not labels (descriptions).
String selectedItem; // for SelectOne list
List<String> selectedItems; // for SelectMany list
public class ListItem {
private String value;
private String label;
public ListItem(String value, String label) {
this.value = value;
this.label = label;
}
public String getValue() {
return value;
}
public String getLabel() {
return label;
}
}
public ListBacker() {}
public ListBacker(List<T> lst) {
put(lst);
}
public void clear() {
contents.clear();
selectedItem = null;
if(selectedItems != null) {
selectedItems.clear();
}
}
public List<ListItem> getContents() {
return convert(contents);
}
public String getSelectedItem() {
return selectedItem;
}
public void setSelectedItem(String selectedItem) {
this.selectedItem = selectedItem;
}
public List<String> getSelectedItems() {
return selectedItems;
}
public void setSelectedItems(List<String> selectedItems) {
this.selectedItems = selectedItems;
}
public T getSelectedItemAsObject() {
return convert(selectedItem);
}
public List<T> getSelectedItemsAsObjects() {
return convert(selectedItems);
}
public void put(T newItem) {
contents.put(newItem.toString(), newItem);
}
public void put(List<T> newItems) {
for (T t : newItems) {
put(t);
}
}
// PROTECTED (UTILITY) METHODS
protected List<ListItem> convert(Map<String, T> maps) {
List<ListItem> lst = new ArrayList<ListItem>();
for (Entry<String, T> e : maps.entrySet()) {
lst.add(new ListItem(e.getKey(), e.getValue().desc()));
}
return lst;
}
protected List<T> convert(List<String> ids) {
List<T> lst = new ArrayList<T>();
for (String id : ids) {
lst.add(convert(id));
}
return lst;
}
protected T convert(String id) {
return contents.get(id);
}
}
I have two toString() implementations, one for JPA entities:
public abstract class AbstractEntityBase {
#Override
public final String toString() {
return String.format("%s[id=%s]", getClass().getSimpleName(), getIdForToString().toString());
}
/**
* Return the entity's ID, whether it is a field or an embedded ID class..
* #return ID Object
*/
protected abstract Object getIdForToString();
}
and one for JPA EmbeddedId's:
public abstract class CompositeKeyBase {
#Override
public final String toString() {
return String.format("%s[id=%s]", getClass().getSimpleName(), getIdForToString());
}
/**
* Supports the class's toString() method, which is required for ListBacker.
* Compile a string of all ID fields, with this format:
* fieldName=StringVALUE,field2=STRINGvAlUE2,...,fieldx=stringvalue <br />
* Recommended: start with Eclipse's "generate toString()" utility and move it to getIdForToString()
* #return a 1-to-1 String representation of the composite key
*/
public abstract String getIdForToString();
}
An example implementation of getIdForToString(), for an entity that has one Id field:
#Override
public Object getIdForToString() {
return userID;
}
An example implementation of getIdForToString(), for an EmbeddedId that has two fields:
#Override
public String getIdForToString() {
return "userID=" + userID + ",roleID=" + roleID;
}

Castle Windsor Typed Factory Facility with generics

I'm trying to register a factory that could resolve an array of event handlers defined as follow:
public interface IEvent { }
public class EventA : IEvent { }
public class EventB : IEvent { }
public class EventC : IEvent { }
public interface IHandler<TEvent> where TEvent : IEvent
{
void Handle(TEvent ev);
}
public class HandlerX : IHandler<EventA>, IHandler<EventB>
{
public void Handle(EventA ev)
{
throw new NotImplementedException("handle EventA");
}
public void Handle(EventB ev)
{
throw new NotImplementedException("handle EventB");
}
}
public class HandlerY : IHandler<EventB>, IHandler<EventC>
{
public void Handle(EventB ev)
{
throw new NotImplementedException("handle EventB");
}
public void Handle(EventC ev)
{
throw new NotImplementedException("handle EventC");
}
}
public interface HandlerFactory
{
object[] GetHandlersForEvent(IEvent ev);
}
Basically for each event I can have more handlers and each handler can handle multiple events. I also want the factory to return object[] because at runtime I don't know what closed generic types would be returned.
I tried the approach descirbed by Krzysztof Koźmic http://kozmic.pl/2010/03/11/advanced-castle-windsor-ndash-generic-typed-factories-auto-release-and-more/
but still have problems.
Basically my question boils down to what types to return from my custom type deriving from DefaultTypedFactoryComponentSelector.
I tried many variations of the following:
public class HandlerSelector : DefaultTypedFactoryComponentSelector
{
protected override TypedFactoryComponent BuildFactoryComponent(MethodInfo method, string componentName, Type componentType, System.Collections.IDictionary additionalArguments)
{
Type eventType = null;
foreach (var k in additionalArguments.Values)
{
eventType = k.GetType();
}
var handlerType = typeof(IHandler<>).MakeGenericType(eventType);
var handlerArrayType = handlerType.MakeArrayType();
//return handlerArrayType;
return new TypedFactoryComponentCollection(handlerType, additionalArguments);
}
protected override Type GetComponentType(MethodInfo method, object[] arguments)
{
return typeof (object);
/*
var message = arguments[0];
var handlerType = typeof(IHandler<>).MakeGenericType(message.GetType());
var handlerArrayType = handlerType.MakeArrayType();
return handlerArrayType;
*/
}
/*
public TypedFactoryComponent SelectComponent(MethodInfo method, Type type, object[] arguments)
{
var message = arguments[0];
var handlerType = typeof(IHandler<>).MakeGenericType(message.GetType());
var result = new TypedFactoryComponentCollection(handlerType.MakeArrayType(), new Arguments(arguments));
return result;
}*/
}
with Windsor installer defined as:
public class Installer : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.AddFacility<TypedFactoryFacility>()
.Register(
Component.For<HandlerSelector>().ImplementedBy<HandlerSelector>(),
Component.For<AutoReleaseHandlerInterceptor>(),
AllTypes.FromAssemblyContaining<Program>()
.BasedOn(typeof(IHandler<>))
.WithService.Base()
.Configure(c => c.LifeStyle.Is(LifestyleType.Transient)
.Interceptors<AutoReleaseHandlerInterceptor>()),
Component.For<HandlerFactory>().AsFactory(c => c.SelectedWith<HandlerSelector>()));
}
}
When calling factory.GetHandlersForEvent(ev); I get an exception complaining about array type mismatch:
"Attempted to access an element as a type incompatible with the array."
Stack trace:
at System.Collections.Generic.Dictionary2.ValueCollection.CopyTo(TValue[] array, Int32 index)
at System.Collections.Generic.Dictionary2.ValueCollection.System.Collections.ICollection.CopyTo(Array array, Int32 index)
at Castle.MicroKernel.DefaultKernel.ResolveAll(Type service, IDictionary arguments) in e:\OSS.Code\Castle.Windsor\src\Castle.Windsor\MicroKernel\DefaultKernel_Resolve.cs:line 285
at Castle.Facilities.TypedFactory.TypedFactoryComponentCollection.Resolve(IKernel kernel) in e:\OSS.Code\Castle.Windsor\src\Castle.Windsor\Facilities\TypedFactory\TypedFactoryComponentCollection.cs:line 39
at Castle.Facilities.TypedFactory.Internal.TypedFactoryInterceptor.Resolve(IInvocation invocation) in e:\OSS.Code\Castle.Windsor\src\Castle.Windsor\Facilities\TypedFactory\Internal\TypedFactoryInterceptor.cs:line 173
at Castle.Facilities.TypedFactory.Internal.TypedFactoryInterceptor.Intercept(IInvocation invocation) in e:\OSS.Code\Castle.Windsor\src\Castle.Windsor\Facilities\TypedFactory\Internal\TypedFactoryInterceptor.cs:line 83
at Castle.DynamicProxy.AbstractInvocation.Proceed()
at Castle.Proxies.HandlerFactoryProxy.GetHandlersForEvent(IEvent ev)
at CastleWindsorTests.Program.TryIt(HandlerFactory factory) in c:\users\user\documents\visual studio 2010\Projects
How to implement the HandlerSelector so that it works well with factory defined as returning object[] whereas the real objects at runtime are closed generic types?
I'll be happy to be pointed to some existing documentation with guidelines for implementors of ITypedFactoryComponentSelector / DefaultTypedFactoryComponentSelector. Yes, I tried the http://docs.castleproject.org/(S(kwaa14uzdj55gv55dzgf0vui))/Windsor.Typed-Factory-Facility-interface-based-factories.ashx but here's not much about the above types.
I really don't want to introduce a service locator (instead of factory) ;).
To answer my own question:
I must've been blind. After reading more closely the xmldoc of the methods I override, changing HandlerSelector to the following solved the problem:
public class HandlerSelector : DefaultTypedFactoryComponentSelector
{
protected override TypedFactoryComponent BuildFactoryComponent(MethodInfo method, string componentName, Type componentType, System.Collections.IDictionary additionalArguments)
{
return new TypedFactoryComponentCollection(componentType, additionalArguments);
}
protected override Type GetComponentType(MethodInfo method, object[] arguments)
{
var message = arguments[0];
var handlerType = typeof(IHandler<>).MakeGenericType(message.GetType());
return handlerType;
}
}
#workabyte
For Castle v3, GetComponentType method stays the same but the BuildFactoryComponent method looks like this for me:
protected override Func<IKernelInternal, IReleasePolicy, object> BuildFactoryComponent(MethodInfo method, string componentName, Type componentType, IDictionary additionalArguments)
{
return (kernel, rp) => kernel.ResolveAll(componentType);
}

Resources