最近老没有时间上来写博文。今天有空来写写上次还没有说完的话题。上一篇提到说说我在WP7应用开发中遇到的 子控件 DataTemplete 中的按钮的命令绑定,刚开始接触似乎是个头疼的问题。那怎么解决呢?

我们仔细想想 silverlight 就是一个庞大的Composite组合模式的实现。包括了我们所说的可视树。不管怎么加Templete,怎么绑定,最终会出现在可视树上。 好就这么探索去吧。。

你会发现Silverlight, WP7中有类似功能的一些绑定中的 RelativeSource。但好像只是预留的接口,有些没有实现。

首先,观看 silverlight4中有未实现完整的相对绑定。

那我们自己来做吧!我们一些基础建设也抄他们的,呵呵

首先定义一些基础枚举:

View Code

public enum RelativeSourceMode{        ParentDataContext = 0,

        FindAncestor = 1

    }}

肯定需要一些相当绑定数据信息,同样参考一下Silverlight4

绑定可能会在同一个控件绑定几个事件,属性所以需要一个集合来管理吧,好做一个简单的。

怎么能给控件一个绑定自定义绑定属性呢? Attache 附加属性 是天生的绝配啊, 给注册一个附加Binding属性 让他可以绑定一个类

,所以做一个抽象的先让数据信息和集合都需继承,这样才能都实用啊。而集合又不需要其他的属性继承下得来,没有意义。 干脆搞个空类:

View Code

public abstract class RelativeSourceBase    {protected RelativeSourceBase()        {

        }    }

参考一下Silverlight4实现相当绑定数据收集工作。

View Code

    public class RelativeSourceBinding : RelativeSourceBase    {

/// <summary>/// Gets or sets the path to the binding source property./// </summary>        public string Path { get; set; }

/// <summary>/// Gets or sets the name of the target dependency property./// </summary>        public string TargetProperty { get; set; }

/// <summary>/// Gets or sets the XAML namespace. This namespace is used to get the class of an attached dependency property./// </summary>        public string TargetNamespace { get; set; }

/// <summary>/// Gets or sets the type of ancestor to look for. /// Define the full name (namespace and class name). Xaml Namespace do not work here./// Example: MyNamespace.MyUserControl or System.Windows.ListBox./// For types in System.Windows.dll you can just use the class name instead of the full name./// </summary>        public string AncestorType { get; set; }

// not implemented yet//public int AncestorLevel { get; set; }

/// <summary>///  Gets or sets a value that describes the location of the binding source relative///  to the position of the binding target./// </summary>        public RelativeSourceMode RelativeMode { get; set; }

/// <summary>///  Gets or sets a value that indicates the direction of the data flow in the binding./// </summary>        public BindingMode BindingMode { get; set; }

/// <summary>/// Gets or sets the converter object that is called by the binding engine to /// modify the data as it is passed between the source and target, or vice versa./// </summary>        public IValueConverter Converter { get; set; }

/// <summary>/// Gets or sets the culture to be used by the System.Windows.Data.Binding.Converter./// </summary>        public CultureInfo ConverterCulture { get; set; }

/// <summary>/// Gets or sets a parameter that can be used in the System.Windows.Data.Binding.Converter logic./// </summary>        public object ConverterParameter { get; set; }

/// <summary>/// Gets or sets a value that indicates whether the System.Windows.FrameworkElement.BindingValidationError event is raised on validation errors./// </summary>        public bool NotifyOnValidationError { get; set; }

/// <summary>/// Gets or sets a value that indicates whether the binding engine will report/// validation errors from an System.ComponentModel.IDataErrorInfo implementation/// on the bound data entity./// </summary>        public bool ValidatesOnDataErrors { get; set; }

/// <summary>/// Gets or sets a value that indicates whether the binding engine will report /// exception validation errors./// </summary>        public bool ValidatesOnExceptions { get; set; }

/// <summary>/// Gets or sets a value that indicates whether the binding engine will report/// validation errors from an System.ComponentModel.INotifyDataErrorInfo implementation/// on the bound data entity./// </summary>        public bool ValidatesOnNotifyDataErrors { get; set; }

internal DependencyProperty TargetDependencyProperty { get; set; }    }

在搞个List来管理多个绑定,让其也继承基类

View Code

public class BindingList : RelativeSourceBase, IList<RelativeSourceBinding>, ICollection<RelativeSourceBinding>, IEnumerable<RelativeSourceBinding>, IList, ICollection, IEnumerable    {

private List<RelativeSourceBinding> _internalList;

public BindingList()        {            _internalList = new List<RelativeSourceBinding>();        }

#region IList<RelativeSourceBinding> Members

public int IndexOf(RelativeSourceBinding item)        {return _internalList.IndexOf(item);        }

public void Insert(int index, RelativeSourceBinding item)        {            _internalList.Insert(index, item);        }

public void RemoveAt(int index)        {            _internalList.RemoveAt(index);        }

public RelativeSourceBinding this[int index]        {get            {return _internalList[index];            }set            {                _internalList[index] = value; ;            }        }

#endregion

#region ICollection<RelativeSourceBinding> Members

public void Add(RelativeSourceBinding item)        {            _internalList.IndexOf(item);        }

public void Clear()        {            _internalList.Clear();        }

public bool Contains(RelativeSourceBinding item)        {return _internalList.Contains(item);        }

public void CopyTo(RelativeSourceBinding[] array, int arrayIndex)        {            _internalList.CopyTo(array, arrayIndex);        }

public int Count        {get { return _internalList.Count; }        }

public bool IsReadOnly        {get { return false; }        }

public bool Remove(RelativeSourceBinding item)        {return _internalList.Remove(item);        }

#endregion

#region IEnumerable<RelativeSourceBinding> Members

public IEnumerator<RelativeSourceBinding> GetEnumerator()        {return _internalList.GetEnumerator();        }

#endregion

#region IEnumerable Members

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()        {return _internalList.GetEnumerator();        }

#endregion

#region IList Members

int IList.Add(object value)        {            _internalList.Add((RelativeSourceBinding)value);return (this.Count - 1);        }

void IList.Clear()        {            _internalList.Clear();        }

bool IList.Contains(object value)        {return _internalList.Contains((RelativeSourceBinding)value);        }

int IList.IndexOf(object value)        {return _internalList.IndexOf((RelativeSourceBinding)value);        }

void IList.Insert(int index, object value)        {            _internalList.Insert(index, (RelativeSourceBinding)value);        }

bool IList.IsFixedSize        {get { return false; }        }

bool IList.IsReadOnly        {get { return false; }        }

void IList.Remove(object value)        {            _internalList.Remove((RelativeSourceBinding)value);        }

void IList.RemoveAt(int index)        {            _internalList.RemoveAt(index);        }

object IList.this[int index]        {get            {return _internalList[index];            }set            {                _internalList[index] = (RelativeSourceBinding)value;            }        }

#endregion

#region ICollection Members

void ICollection.CopyTo(Array array, int index)        {throw new NotImplementedException();        }

int ICollection.Count        {get { return _internalList.Count; }        }

bool ICollection.IsSynchronized        {get { return false; }        }

object ICollection.SyncRoot        {get { return _internalList; }        }

#endregion    }

数据搞定了,现在主攻逻辑实现了。。

1.实现附加属性。

2.分析附加属性绑定配置数据信息。

3.查找可视树找到对应UI元素

4.创建绑定。这是时候遇到了问题,需要多重"."属性分析。 还有绑定目标中是否通过名称怎么分析Type? 还好查资料有很多类型的分析代码。

View Code

[ContentProperty("Binding")]public static class BindingAdapter    {

#region Binding (Attached DependencyProperty)

public static RelativeSourceBase GetBinding(DependencyObject obj)        {return (RelativeSourceBase)obj.GetValue(BindingProperty);        }

public static void SetBinding(DependencyObject obj, RelativeSourceBase value)        {            obj.SetValue(BindingProperty, value);        }

public static readonly DependencyProperty BindingProperty = DependencyProperty.RegisterAttached("Binding", typeof(RelativeSourceBase), typeof(BindingAdapter), new PropertyMetadata(null, OnBinding));

private static void OnBinding(DependencyObject depObj, DependencyPropertyChangedEventArgs e)        {            FrameworkElement targetElement = depObj as FrameworkElement;

if (targetElement != null)            {// attach loading event                targetElement.Loaded += new RoutedEventHandler(targetElement_Loaded);                targetElement.Unloaded += new RoutedEventHandler(targetElement_Unloaded);            }        }

#endregion

#region Private methods

private static void targetElement_Loaded(object sender, RoutedEventArgs e)        {try            {                FrameworkElement targetElement = sender as FrameworkElement;

// release handler to prevent memory leaks                targetElement.Loaded -= new RoutedEventHandler(targetElement_Loaded);

                RelativeSourceBase bindings = GetBinding(targetElement);

if (bindings is RelativeSourceBinding)                {// get the binding configuration                    RelativeSourceBinding bindingConfiguration = bindings as RelativeSourceBinding;                    ProcessBinding(targetElement, bindingConfiguration);                }else if (bindings is BindingList)                {// get the binding configuration                    BindingList list = bindings as BindingList;

foreach (RelativeSourceBinding bindingConfiguration in list)                    {                        ProcessBinding(targetElement, bindingConfiguration);                    }                }

            }catch (Exception ex)            {// ignore this exception, because the SL binding engine does not throw exceptions when a binding is wrong.            }        }

static void targetElement_Unloaded(object sender, RoutedEventArgs e)        {try            {                FrameworkElement targetElement = sender as FrameworkElement;                targetElement.Unloaded -= new RoutedEventHandler(targetElement_Unloaded);

                RelativeSourceBase bindings = GetBinding(targetElement);

if (bindings is RelativeSourceBinding)                {// get the binding configuration                    RelativeSourceBinding bindingConfiguration = bindings as RelativeSourceBinding;if (bindingConfiguration.TargetDependencyProperty != null)                        targetElement.ClearValue(bindingConfiguration.TargetDependencyProperty);                }else if (bindings is BindingList)                {// get the binding configuration                    BindingList list = bindings as BindingList;

foreach (RelativeSourceBinding bindingConfiguration in list)                    {if (bindingConfiguration.TargetDependencyProperty != null)                            targetElement.ClearValue(bindingConfiguration.TargetDependencyProperty);                    }                }            }catch            {            }        }

private static void ProcessBinding(FrameworkElement targetElement, RelativeSourceBinding bindingConfiguration)        {

if (bindingConfiguration.RelativeMode == RelativeSourceMode.FindAncestor &&!string.IsNullOrEmpty(bindingConfiguration.AncestorType))            {// navigate up the tree to find the type                DependencyObject currentObject = VisualTreeHelper.GetParent(targetElement);

                DependencyObject candidate = null;                DependencyObject ancestor = null;

while (true)                {if (currentObject == null)                    {break;                    }

                    Type currentType = currentObject.GetType();

while (currentType != null && currentType.IsSubclassOf(typeof(DependencyObject)))                    {if (currentType.FullName == bindingConfiguration.AncestorType)                        {                            ancestor = currentObject;break;                        }

// for types in assemblies System.Windows, System.Windows.Controls, System.Windows.Controls.Data, etc, // its possible to define just the class name instead of the full class name including the namespace.                        if (candidate == null && currentType.Name == bindingConfiguration.AncestorType && currentType.Assembly.FullName.StartsWith("System.Windows"))                        {// the name of the element is matching, but it is not the fullname.// remeber the element in case if no element is matching to the ancestor type name                            candidate = currentObject;                        }

// next type up the hierarchy                        currentType = currentType.BaseType;                    }

// next parent                                        currentObject = VisualTreeHelper.GetParent(currentObject);                }

// concrete                if (ancestor == null)                {                    ancestor = candidate;                }

if (ancestor != null && ancestor is FrameworkElement)                {// bind them                    CreateBinding(targetElement, ancestor, bindingConfiguration);                }            }else if (bindingConfiguration.RelativeMode == RelativeSourceMode.ParentDataContext)            {object currentDataContext = targetElement.DataContext;

// navigate up the tree to find the parent datacontext                DependencyObject currentObject = VisualTreeHelper.GetParent(targetElement);

while (true)                {if (currentObject == null)break;

                    FrameworkElement fe = currentObject as FrameworkElement;

if (fe != null)                    {if (fe.DataContext != null && fe.DataContext != currentDataContext)                        {// bind them                            CreateBinding(targetElement, fe.DataContext, bindingConfiguration);break;                        }                    }

// next parent                                        currentObject = VisualTreeHelper.GetParent(currentObject);                }

            }        }

private static List<string> GetClassNames(Type type)        {            List<string> result = new List<string>();

// check            if (type == null && type.IsSubclassOf(typeof(DependencyObject)))return result;

// process            do            {                result.Add(type.FullName);                type = type.BaseType;            } while (type != null && type.IsSubclassOf(typeof(DependencyObject)));

// return            return result;        }

private static void CreateBinding(FrameworkElement targetElement, object sourceElement, RelativeSourceBinding bindingConfiguration)        {// input check            if (targetElement == null)return;if (sourceElement == null)return;if (bindingConfiguration == null)return;

// check binding configuration// ...target property must be set            if (bindingConfiguration.TargetProperty.IsNullOrWhiteSpace())return;// ...path property must be set            if (bindingConfiguration.Path.IsNullOrWhiteSpace())return;

// support of attached property binding syntax: TargetProperty='(Grid.Row)'            string targetPropertyName = (bindingConfiguration.TargetProperty + "").Trim().TrimStart('(').TrimEnd(')') + "Property";

// find the target dependency property            DependencyProperty targetDependencyProperty = null;if (targetPropertyName.Contains("."))            {// it is an attached dependency property                string[] parts = targetPropertyName.Split('.');

if (parts.Length == 2 && !parts[0].IsNullOrWhiteSpace() && !parts[1].IsNullOrWhiteSpace())                {                    Type attachedType = TypeLoader.GetType(parts[0], bindingConfiguration.TargetNamespace);

if (attachedType != null)                    {                        FieldInfo[] targetFields = attachedType.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);                        FieldInfo targetDependencyPropertyField = targetFields.FirstOrDefault(i => i.Name == parts[1]);if (targetDependencyPropertyField != null)                            targetDependencyProperty = targetDependencyPropertyField.GetValue(null) as DependencyProperty;                    }                }            }else            {// it is a standard dependency property                FieldInfo[] targetFields = targetElement.GetType().GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);                FieldInfo targetDependencyPropertyField = targetFields.FirstOrDefault(i => i.Name == targetPropertyName);

if (targetDependencyPropertyField != null)                    targetDependencyProperty = targetDependencyPropertyField.GetValue(null) as DependencyProperty;            }

// set binding            if (targetDependencyProperty != null)            {

if (bindingConfiguration.TargetDependencyProperty != null&& bindingConfiguration.TargetDependencyProperty != targetDependencyProperty)                    targetElement.ClearValue(bindingConfiguration.TargetDependencyProperty);

                bindingConfiguration.TargetDependencyProperty = targetDependencyProperty;

                Binding binding = new Binding();                binding.Source = sourceElement;                binding.Path = new PropertyPath(bindingConfiguration.Path);                binding.Mode = bindingConfiguration.BindingMode;                binding.Converter = bindingConfiguration.Converter;                binding.ConverterParameter = bindingConfiguration.ConverterParameter;                binding.ConverterCulture = bindingConfiguration.ConverterCulture;                binding.NotifyOnValidationError = bindingConfiguration.NotifyOnValidationError;#if !WINDOWS_PHONE                binding.ValidatesOnDataErrors = bindingConfiguration.ValidatesOnDataErrors;#endif                binding.ValidatesOnExceptions = bindingConfiguration.ValidatesOnExceptions;#if !WINDOWS_PHONE                binding.ValidatesOnNotifyDataErrors = bindingConfiguration.ValidatesOnNotifyDataErrors;#endif// set the binding on our target element                targetElement.SetBinding(targetDependencyProperty, binding);            }        }

#endregion    }

也把这个XMAL类型分析的小工具代码转给大家吧

View Code

/// <summary>/// Provides functionality to load any type with its class name, namespace and assembly-name within the Silverlight environment./// </summary>/// <remarks>/// The Type.GetType method is different in Silverlight than in the standard .NET runtime. In Silverlight we have to provide the /// fully qualified assembly name to get a type in a custom assembly. Only build in controls or types in the same assembly are /// excluded from this rule. Full qualified assembly name means a syntax like the following: /// MyComponent.MyType, MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=4bec85d7bec6698f./// This class uses the XamlReader capability to resolve type during parsing a xaml-string. While this is a little time consuming/// the TypeLoader maintains a cache to get types faster./// </remarks>    public static class TypeLoader    {// cache for resolved type        private static Dictionary<string, Type> _cache = new Dictionary<string, Type>();

/// <summary>/// Gets the System.Type with the specified name, name space and assembly name./// </summary>/// <param name="className">The class name without namespace.</param>/// <param name="nameSpace">The name space</param>/// <param name="assemblyName">The name of the assembly containing the type.</param>/// <returns>The type matching the provided parameters or null if not found.</returns>        //[DebuggerStepThrough()]        public static Type GetType(string className, string nameSpace, string assemblyName)        {// check            if (nameSpace.IsNullOrWhiteSpace())return null;

string xamlNamespace = string.Format("clr-namespace:{0}", nameSpace);// assembly name is optional            if (!assemblyName.IsNullOrWhiteSpace())                xamlNamespace += string.Format(";assembly={0}", assemblyName);

return GetType(className, xamlNamespace);        }

/// <summary>/// Gets the System.Type with the specified name. /// This method overload can be used for:/// 1. core controls such as Button, Grid, ListBox, etc. without specifying the namespace or assembly name./// 2. with the qualified assembly name of the type without version and public key token like this: "MyNamespace.MyType, MyAssembly"./// </summary>/// <param name="className">Pure class name of Core Controls such as Button, Grid, ListBox, etc.</param>/// <returns>The type matching the provided parameters or null if not found.</returns>        //[DebuggerStepThrough()]        public static Type GetType(string className)        {if (className != null && className.Contains(","))            {string[] qualifiedNameParts = className.Split(',');

if (qualifiedNameParts.Length == 2)                {string[] fullClassNameParts = qualifiedNameParts[0].Split('.');

if (fullClassNameParts.Length > 0)                    {// classname                        string newClassName = fullClassNameParts.Last().Trim();

// namespace                        string nameSpace = "";for (int i = 0; i < fullClassNameParts.Length - 1; i++)                        {                            nameSpace += fullClassNameParts[i] + ".";                        }                        nameSpace = nameSpace.TrimEnd('.');

string assemblyName = qualifiedNameParts[1].Trim();

return GetType(newClassName, nameSpace, assemblyName);                    }                }

            }

return GetType(className, "");        }

/// <summary>/// Gets the System.Type with the specified name. The xaml namespace specifies the namespace and assembly name in the same syntax as in xaml. /// </summary>/// <param name="className">The class name without namespace.</param>/// <param name="xamlNamespace">/// The xaml namespace. This is the same syntax as used in XAML syntax. /// Example: "clr-namespace:MyComponent.SubNamespace;assembly=MyAssemblyName/// </param>/// <returns>The type matching the provided parameters or null if not found.</returns>        //[DebuggerStepThrough()]        public static Type GetType(string className, string xamlNamespace)        {// check input            if (className.IsNullOrWhiteSpace())return null;

if (className.Contains("."))throw new ArgumentException("className must not include the namespace. Please provide namespace with separate parameter.");

// check if type is already in cache            string key = xamlNamespace + "&" + className;

if (_cache.ContainsKey(key))return _cache[key];

lock (_cache)            {try                {// check again because another thread might be faster and has already created the cache-entry                    if (_cache.ContainsKey(key))return _cache[key];

// create xaml with a simply Style element and set the TargetType property with the provided type name                    string xaml = "<Style xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' ";

// set the xaml namesapce if provided                    if (!xamlNamespace.IsNullOrWhiteSpace())                    {                        xaml += string.Format("xmlns:tmp='{0}' TargetType='tmp:{1}' />", xamlNamespace, className);                    }else                    {// Core controls such as Button, Grid, ListBox, etc do not need a namespace                        xaml += string.Format("TargetType='{0}' />", className);                    }

// let the XamlParser load the type via the TargetType property                     Style style = XamlReader.Load(xaml) as Style;

if (style != null)                    {                        Type targetType = style.TargetType;                        AddToCache(key, targetType);return targetType;                    }                }catch (Exception ex)                {// Try to load type in executing assembly                    if (!xamlNamespace.IsNullOrWhiteSpace())                    {// note: Type.GetType uses needs assembly-qualified name of the type to get. If the type is //       in the currently executing assembly or in Mscorlib.dll, it is sufficient to supply //       the type name qualified by its namespace.                        Type type = Type.GetType(string.Format("{0}.{1}", xamlNamespace.Replace("clr-namespace:", "").TrimEnd(';'), className));

if (type != null)                        {// add to cache                            AddToCache(key, type);return type;                        }                    }

//****** DONT SET VALUE TO NULL, BECAUSE OF CASES WHEN AN ASSEMBLY IS  *****//****** LOADED DYNAMICALLY INTO THE APPLICATION DOMAIN                *****// don't let the exception repeat. Set null as cache value                    AddToCache(key, null);//**************************************************************************/                }            }

return null;        }

private static void AddToCache(string key, Type type)        {            _cache.Add(key, type);            CompositionTarget.Rendering -= new EventHandler(CompositionTarget_Rendering);            CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering);        }

static void CompositionTarget_Rendering(object sender, EventArgs e)        {            CompositionTarget.Rendering -= new EventHandler(CompositionTarget_Rendering);            _cache.Clear();        }

    }

至此快成功了试一下:

<my:CommandButton CommandParameter="{Binding}" >
       <localBinding:BindingAdapter.Binding>
              <localBinding:RelativeSourceBinding Path="ClickCommmand" TargetProperty="Command"
                                 RelativeMode="ParentDataContext" />

</localBinding:BindingAdapter.Binding>

......................

<my:CommandButton CommandParameter="{Binding}" >
          <localBinding:BindingAdapter.Binding>
                <localBinding:RelativeSourceBinding Path="DataContext.ClickCommmand" TargetProperty="Command"
                              RelativeMode="FindAncestor" AncestorType="Grid" />

</localBinding:BindingAdapter.Binding>

.............

View Code

<ComboBox Grid.Column="1"><local:BindingAdapter.Binding><local:BindingList><local:RelativeSourceBinding Path="DataContext.Picklist" TargetProperty="ItemsSource" RelativeMode="FindAncestor" AncestorType="UserControl" /><local:RelativeSourceBinding Path="DataContext.Tooltip"TargetProperty="(ToolTipService.ToolTip)" RelativeMode="FindAncestor"AncestorType="UserControl" /><local:RelativeSourceBinding Path="DataContext.Tooltip" TargetProperty="(DemoAttachedElement.Value)"TargetNamespace="clr-namespace:********;assembly=*******" RelativeMode="FindAncestor" AncestorType="UserControl" /></local:BindingList></local:BindingAdapter.Binding></ComboBox>

  

转载于:https://www.cnblogs.com/zhouhoujun/archive/2011/07/18/2109067.html

在WP7下自定义RelativeSource 的Binding相关推荐

  1. opensuse-KDE桌面下自定义快捷键,ctrl+alt+t打开konsole

    2019独角兽企业重金招聘Python工程师标准>>> opensuse-KDE桌面下自定义快捷键,ctrl+alt+t打开konsole 转载于:https://my.oschin ...

  2. 异贝,通过移动互联网技术,为中小微实体企业联盟、线上链接、线上线下自定义营销方案推送。案例62

    欢迎关注异贝.异贝5G营销工具,今天给大家带来的是体育用品店的营销案例: 生命不止,运动不息.许多人都爱运动,爱体育,但随着社会发展,越来越少人会去到传统的体育用品店购买运动用品.一方面原因是电商的发 ...

  3. 异贝,通过移动互联网技术,为中小微实体企业联盟、线上链接、线上线下自定义营销方案推送。案例52

    欢迎关注异贝.异贝5G营销工具,今天给大家带来的案例是小超市的营销方案: 随着经济的不断发展,越来越多的大型企业都看中了四五线县城的人口和消费能力,许多深耕当地的经营场所,都收到了这些"外来 ...

  4. 异贝,通过移动互联网技术,为中小微实体企业联盟、线上链接、线上线下自定义营销方案推送。案例53

    欢迎关注异贝.异贝5G营销工具,今天给大家带来的案例是桌游店的营销方案: 随着娱乐至上的时代来临,各式各样的游戏.项目层出不穷,而其中最火热的闲暇娱乐项目,要数因手游而孕育而生的"剧本杀&q ...

  5. 异贝5G新零售工具,通过移动互联网技术,为中小微实体企业联盟、线上链接、线上线下自定义营销方案的推送。

    异贝通过移动互联网技术应用,为中国实体企业实现企业联盟.线上链接.线上线下自定义营销方案的推送.实体企业互联网平台搭建:各种系统研发及技术智慧输出的一站式营销孵化综合服务科技平台! 经过团队的努力与发 ...

  6. 异贝,移动互联网技术,为中小微实体企业联盟、线上链接、线上线下自定义营销方案推送。案例42

    欢迎关注异贝.异贝5G营销工具,为实体商家科技赋能,今天给大家带来的案例是羊毛衫店的营销: 人天生就有爱占便宜的本性,这在消费者心理学中被称作合算偏见,人们在交易的时候,不仅要买商品,也要买商品时占到 ...

  7. 异贝,通过移动互联网技术,为中小微实体企业联盟、线上链接、线上线下自定义营销方案推送。案例69

    欢迎关注异贝.异贝5G营销工具.今天给大家带来的是服装店的营销案例: 今天分享的案例是一位浙江的美女所开的一家服装店,在服装店刚开始营业的那段时间里,由于靠着父母的资源和关系,小朱的服装店在当地服装圈 ...

  8. 异贝,通过移动互联网技术,为中小微实体企业联盟、线上链接、线上线下自定义营销方案推送。案例60

    欢迎关注异贝.异贝5G营销工具,今天给大家带来的案例是儿童玩具市场的营销案例: 现在的儿童玩具市场,既有越来越旺盛的趋势,却也同样面临着的激烈的竞争.除了原来卖玩具的同行的竞争,还有各个教育机构也在出 ...

  9. 异贝,通过移动互联网技术,为中小微实体企业联盟、线上链接、线上线下自定义营销方案推送。案例55

    欢迎关注异贝.异贝5G营销工具,今天给大家带来的案例是ktv的营销方案: 现在很多的KTV基本上都会上美团.大众等团购网以低价,甚至超低价来吸引顾客,然后会以酒水.零食.小吃.拼盘等赚钱,说白了就是先 ...

最新文章

  1. Protoc Buffer 优化传输大小的一个细节
  2. 机器学习笔记:岭回归(L2正则化)
  3. MySQL-binlog格式对主从复制的影响MySQL主从复制的过程
  4. 深究AngularJS——校验(非form表单)
  5. Keras Data augmentation(数据扩充)
  6. 强化学习原理与python实现原理pdf_纯Python实现!Facebook发布PyTorch分布式强化学习库...
  7. 成交量与股价的关系图解
  8. 80-10-010-原理-Java NIO-简介
  9. python预测实例教程_手把手教你用Python库Keras做预测(附代码)-阿里云开发者社区...
  10. Code4Fun: 通过XML模板系统实现对象的灵活序列化
  11. 10 LVS负载均衡群集-NAT
  12. 爱心函数可视化 python
  13. html标签img是什么意思,html中img标签属性是什么意思
  14. Java爬虫彼岸桌面壁纸(使用httpClient+Jsoup)
  15. c语言建立并存储树,利用十字链表存储树结构(便于同时求出某一点的入度与出度)------C语言实现...
  16. kettle用命令行执行ktr和kjb
  17. java 学生兼职_javaweb大学生兼职平台
  18. 计算机引起usb设备无法识别的原因有哪些,计算机无法识别USB设备是什么原因
  19. sql 语句中count()条件计数
  20. 【C#】WPF的xaml中定义的Trigger为什么有时候会不管用,如Border的MouseOver之类的

热门文章

  1. php多表头表格,HTML多表头表格代码示例
  2. mysql mysql_row 整行数据_PHP使用mysql_fetch_row查询获得数据行列表的方法,phpmysql_fetch_row_PHP教程...
  3. matlab画三维图
  4. zynq学习02 新建一个Helloworld工程
  5. php采集列表xml代码,php读取xml列表程序
  6. python bar
  7. RUST等差分解一个数
  8. 突然想到一个可以减少fc层权重数的方法
  9. pandas版xml json excel互转
  10. 光伏行业需理性看待低价中标 市场竞争是必然选择